8e2a7c74e9a9d54dbc5ed15755aac831cf1cf14b
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>
44 #include <stdbool.h>
46 /* RM external API includes */
47 #include <ti/drv/rm/rm.h>
49 /* RM internal API includes */
50 #include <ti/drv/rm/include/rm_allocatorloc.h>
51 #include <ti/drv/rm/include/rm_policyloc.h>
52 #include <ti/drv/rm/include/rm_dtb_utilloc.h>
54 /* RM LIBFDT includes */
55 #include <ti/drv/rm/util/libfdt/libfdt.h>
57 /* Tree algorithm includes */
58 #include <ti/drv/rm/util/tree.h>
60 /* RM OSAL layer */
61 #include <rm_osal.h>
63 /**********************************************************************
64 *********************** Policy Globals *******************************
65 **********************************************************************/
67 /* Character used in Policies to specify all RM instances receive
68 * the defined permissions for a resource node */
69 const char Rm_policyAllInstances[] = "*";
71 /**********************************************************************
72 ******************** Local Policy Functions **************************
73 **********************************************************************/
75 /* FUNCTION PURPOSE: Validates the instance names in a permissions string
76 ***********************************************************************
77 * DESCRIPTION: Returns RM_OK if all the instance names in a permissions
78 * string match instance names defined in the valid instance
79 * list. RM_ERROR_PERM_STR_INST_NOT_VALID is returned if
80 * there are any mismatches
81 */
82 static int32_t policyCheckInstances(Rm_PolicyValidInstTree *validInstTree,
83 Rm_PolicyPermission *permissionsList)
84 {
85 while (permissionsList) {
86 if (strncmp(permissionsList->instName, Rm_policyAllInstances, RM_NAME_MAX_CHARS) &&
87 (!rmPolicyGetValidInstNode(validInstTree, permissionsList->instName))) {
88 return(RM_ERROR_PERM_STR_INST_NOT_VALID);
89 }
90 permissionsList = permissionsList->nextPermission;
91 }
92 return(RM_OK);
93 }
95 /* FUNCTION PURPOSE: Parses a permissions subgroup
96 ***********************************************************************
97 * DESCRIPTION: Returns a linked list of policy permissions defining
98 * which RM instance referenced in the permissions subgroup
99 * get which permissions. Returns NULL if any syntax
100 * errors are encountered during the parsing. The error
101 * is returned via the result pointer parameter.
102 */
103 static Rm_PolicyPermission *policyParseSubPermission(char *permStrStart, char *permStrEnd,
104 int32_t *result)
105 {
106 Rm_PolicyPermission *startPerm = NULL;
107 Rm_PolicyPermission *newPerm = NULL;
108 Rm_PolicyPermission *prevPerm = NULL;
109 Rm_PolicyPermission *nextPerm = NULL;
110 char *permStrPtr = NULL;
111 char *subgroupStart = NULL;
112 char *subgroupEnd = NULL;
113 uint32_t permStrLen = (uint32_t)(permStrEnd - permStrStart + 1);
114 char instNameTemp[RM_NAME_MAX_CHARS];
115 uint32_t instNameIndex;
116 bool foundInstName;
117 bool instNameComplete;
118 bool assignmentLeft;
119 bool assignmentRight;
121 /* Create a local copy of the sub-permission string */
122 permStrPtr = Rm_osalMalloc(permStrLen);
123 strncpy(permStrPtr, permStrStart, permStrLen);
124 /* Make sure the last character in the copied sub-permission string is null */
125 permStrPtr[permStrLen - 1] = '\0';
127 permStrStart = permStrPtr;
128 permStrEnd = permStrPtr + strlen(permStrPtr);
130 /* Find the beginning and end of the sub-permission instance group */
131 subgroupStart = strchr(permStrStart, RM_POLICY_PERM_SUBGROUP_START);
132 subgroupEnd = strchr(permStrStart, RM_POLICY_PERM_SUBGROUP_END);
134 if ((!subgroupStart) || (!subgroupEnd) || (subgroupStart > subgroupEnd) ||
135 ((subgroupStart != strrchr(permStrStart, RM_POLICY_PERM_SUBGROUP_START)) &&
136 (subgroupEnd != strrchr(permStrStart, RM_POLICY_PERM_SUBGROUP_END)))) {
137 /* Free the memory associated with the temp string and return an error if:
138 * a) Could not find the instance group start
139 * b) Could not find the instance group end
140 * c) Subgroup start and end are out of order
141 * d) There is more than one instance subgroup specified in the string. There
142 * should only be one subgroup per sub-permission string */
143 Rm_osalFree((void *)permStrStart, permStrLen);
144 *result = RM_ERROR_PERM_STR_TOO_MANY_INST_GROUPS;
145 return(NULL);
146 }
148 /* Create a permission entry for each instance specified in the instance group.
149 * Instances names are separated by one or more spaces. */
150 permStrPtr = subgroupStart + 1;
151 instNameIndex = 0;
152 foundInstName = false;
153 instNameComplete = false;
154 while (permStrPtr <= subgroupEnd) {
155 if ((isspace(*permStrPtr) || (*permStrPtr == RM_POLICY_PERM_SUBGROUP_END))
156 && foundInstName) {
157 /* First space encountered after copying an instance name. This
158 * terminates the instance name. All other space characters are
159 * ignored. */
160 instNameTemp[instNameIndex] = '\0';
161 instNameComplete = true;
162 }
163 else {
164 if (!foundInstName) {
165 /* First non-whitespace character encountered is the start of an
166 * instance name */
167 foundInstName = true;
168 }
170 /* Copy the character into the temporary instance name string */
171 instNameTemp[instNameIndex++] = *permStrPtr;
172 }
174 if (instNameComplete) {
175 newPerm = (Rm_PolicyPermission *) Rm_osalMalloc(sizeof(Rm_PolicyPermission));
176 memset((void *)newPerm, 0, sizeof(Rm_PolicyPermission));
178 strncpy(newPerm->instName, instNameTemp, RM_NAME_MAX_CHARS);
179 newPerm->nextPermission = NULL;
181 if (prevPerm == NULL) {
182 /* Save the first instance so it can be returned */
183 startPerm = newPerm;
184 }
185 else {
186 prevPerm->nextPermission = newPerm;
187 }
188 prevPerm = newPerm;
190 instNameComplete = false;
191 instNameIndex = 0;
192 foundInstName = false;
193 }
194 else if (instNameIndex == RM_NAME_MAX_CHARS) {
195 /* Instance name is longer than max length */
196 while (startPerm) {
197 nextPerm = startPerm->nextPermission;
198 Rm_osalFree((void *)startPerm, sizeof(Rm_PolicyPermission));
199 startPerm = nextPerm;
200 }
201 Rm_osalFree((void *)permStrStart, sizeof(permStrLen));
202 *result = RM_ERROR_INST_NAME_IN_ASSIGNMENT_TOO_LONG;
203 return(NULL);
204 }
206 permStrPtr++;
207 }
209 /* Fill in the permissions for each instance name */
211 /* Look on left of instance group for permission assignments. */
212 permStrPtr = subgroupStart - 1;
213 assignmentLeft = false;
214 while (permStrPtr >= permStrStart)
215 {
216 if (*permStrPtr == RM_POLICY_PERM_ASSIGNMENT) {
217 if (assignmentLeft) {
218 /* Assignment character has been found more than once. This is a
219 * syntax error. Free the permission list and the temporary string
220 * and return. */
221 while (startPerm) {
222 nextPerm = startPerm->nextPermission;
223 Rm_osalFree((void *)startPerm, sizeof(Rm_PolicyPermission));
224 startPerm = nextPerm;
225 }
226 Rm_osalFree((void *)permStrStart, sizeof(permStrLen));
227 *result = RM_ERROR_PERM_STR_TOO_MANY_ASSIGN_CHARS;
228 return(NULL);
229 }
230 else {
231 assignmentLeft = true;
232 }
233 }
234 else if (!isspace(*permStrPtr)) {
235 if (assignmentLeft) {
236 if ((*permStrPtr == RM_POLICY_PERM_INIT_LOWER) ||
237 (*permStrPtr == RM_POLICY_PERM_INIT_UPPER)) {
238 newPerm = startPerm;
239 while (newPerm) {
240 RM_policy_SET_PERM(newPerm->permissionBits, RM_POLICY_PERM_INIT_SHIFT, 1);
241 newPerm = newPerm->nextPermission;
242 }
243 }
244 else if ((*permStrPtr == RM_POLICY_PERM_USE_LOWER) ||
245 (*permStrPtr == RM_POLICY_PERM_USE_UPPER)) {
246 newPerm = startPerm;
247 while (newPerm) {
248 RM_policy_SET_PERM(newPerm->permissionBits, RM_POLICY_PERM_USE_SHIFT, 1);
249 newPerm = newPerm->nextPermission;
250 }
251 }
252 else if ((*permStrPtr == RM_POLICY_PERM_EXCLUSIVE_LOWER) ||
253 (*permStrPtr == RM_POLICY_PERM_EXCLUSIVE_UPPER)) {
254 newPerm = startPerm;
255 while (newPerm) {
256 RM_policy_SET_PERM(newPerm->permissionBits, RM_POLICY_PERM_EXCLUSIVE_SHIFT, 1);
257 newPerm = newPerm->nextPermission;
258 }
259 }
260 else if ((*permStrPtr == RM_POLICY_PERM_SHARED_LINUX_LOWER) ||
261 (*permStrPtr == RM_POLICY_PERM_SHARED_LINUX_UPPER)) {
262 newPerm = startPerm;
263 while (newPerm) {
264 RM_policy_SET_PERM(newPerm->permissionBits, RM_POLICY_PERM_SHARED_LINUX_SHIFT, 1);
265 newPerm = newPerm->nextPermission;
266 }
267 }
268 else {
269 /* Invalid permission character. This is a
270 * syntax error. Free the permission list and the temporary string
271 * and return. */
272 while (startPerm) {
273 nextPerm = startPerm->nextPermission;
274 Rm_osalFree((void *)startPerm, sizeof(Rm_PolicyPermission));
275 startPerm = nextPerm;
276 }
277 Rm_osalFree((void *)permStrStart, sizeof(permStrLen));
278 *result = RM_ERROR_PERM_STR_INVALID_CHAR;
279 return(NULL);
280 }
281 }
282 else {
283 /* Character found without the assignment character being found. This is a
284 * syntax error. Free the permission list and the temporary string
285 * and return. */
286 while (startPerm) {
287 nextPerm = startPerm->nextPermission;
288 Rm_osalFree((void *)startPerm, sizeof(Rm_PolicyPermission));
289 startPerm = nextPerm;
290 }
291 Rm_osalFree((void *)permStrStart, sizeof(permStrLen));
292 *result = RM_ERROR_PERM_CHAR_WITHOUT_ASSIGN_CHAR;
293 return(NULL);
294 }
295 }
296 permStrPtr--;
297 }
299 /* Look on right of instance group for permission assignments. */
300 permStrPtr = subgroupEnd + 1;
301 assignmentRight = false;
302 while (permStrPtr < permStrEnd) {
303 if (assignmentLeft && (!isspace(*permStrPtr))) {
304 /* There should be nothing but spaces on right if assignment was already found on left */
305 while (startPerm) {
306 nextPerm = startPerm->nextPermission;
307 Rm_osalFree((void *)startPerm, sizeof(Rm_PolicyPermission));
308 startPerm = nextPerm;
309 }
310 Rm_osalFree((void *)permStrStart, sizeof(permStrLen));
311 *result = RM_ERROR_INVALID_PERMS_CHAR_ON_RIGHT;
312 return(NULL);
313 }
315 if (*permStrPtr == RM_POLICY_PERM_ASSIGNMENT) {
316 if (assignmentRight) {
317 /* Assignment character has been found more than once. This is a
318 * syntax error. Free the permission list and the temporary string
319 * and return. */
320 while (startPerm) {
321 nextPerm = startPerm->nextPermission;
322 Rm_osalFree((void *)startPerm, sizeof(Rm_PolicyPermission));
323 startPerm = nextPerm;
324 }
325 Rm_osalFree((void *)permStrStart, sizeof(permStrLen));
326 *result = RM_ERROR_PERM_STR_TOO_MANY_ASSIGN_CHARS;
327 return(NULL);
328 }
329 else {
330 assignmentRight = true;
331 }
332 }
333 else if (!isspace(*permStrPtr)) {
334 if (assignmentRight) {
335 if ((*permStrPtr == RM_POLICY_PERM_INIT_LOWER) ||
336 (*permStrPtr == RM_POLICY_PERM_INIT_UPPER)) {
337 newPerm = startPerm;
338 while (newPerm) {
339 RM_policy_SET_PERM(newPerm->permissionBits, RM_POLICY_PERM_INIT_SHIFT, 1);
340 newPerm = newPerm->nextPermission;
341 }
342 }
343 else if ((*permStrPtr == RM_POLICY_PERM_USE_LOWER) ||
344 (*permStrPtr == RM_POLICY_PERM_USE_UPPER)) {
345 newPerm = startPerm;
346 while (newPerm) {
347 RM_policy_SET_PERM(newPerm->permissionBits, RM_POLICY_PERM_USE_SHIFT, 1);
348 newPerm = newPerm->nextPermission;
349 }
350 }
351 else if ((*permStrPtr == RM_POLICY_PERM_EXCLUSIVE_LOWER) ||
352 (*permStrPtr == RM_POLICY_PERM_EXCLUSIVE_UPPER)) {
353 newPerm = startPerm;
354 while (newPerm) {
355 RM_policy_SET_PERM(newPerm->permissionBits, RM_POLICY_PERM_EXCLUSIVE_SHIFT, 1);
356 newPerm = newPerm->nextPermission;
357 }
358 }
359 else if ((*permStrPtr == RM_POLICY_PERM_SHARED_LINUX_LOWER) ||
360 (*permStrPtr == RM_POLICY_PERM_SHARED_LINUX_UPPER)) {
361 newPerm = startPerm;
362 while (newPerm) {
363 RM_policy_SET_PERM(newPerm->permissionBits, RM_POLICY_PERM_SHARED_LINUX_SHIFT, 1);
364 newPerm = newPerm->nextPermission;
365 }
366 }
367 else {
368 /* Invalid permission character. This is a
369 * syntax error. Free the permission list and the temporary string
370 * and return. */
371 while (startPerm) {
372 nextPerm = startPerm->nextPermission;
373 Rm_osalFree((void *)startPerm, sizeof(Rm_PolicyPermission));
374 startPerm = nextPerm;
375 }
376 Rm_osalFree((void *)permStrStart, sizeof(permStrLen));
377 *result = RM_ERROR_PERM_STR_INVALID_CHAR;
378 return(NULL);
379 }
380 }
381 else {
382 /* Character found without the assignment character being found. This is a
383 * syntax error. Free the permission list and the temporary string
384 * and return. */
385 while (startPerm) {
386 nextPerm = startPerm->nextPermission;
387 Rm_osalFree((void *)startPerm, sizeof(Rm_PolicyPermission));
388 startPerm = nextPerm;
389 }
390 Rm_osalFree((void *)permStrStart, sizeof(permStrLen));
391 *result = RM_ERROR_PERM_STR_TOO_MANY_ASSIGN_CHARS;
392 return(NULL);
393 }
394 }
395 permStrPtr++;
396 }
398 Rm_osalFree((void *)permStrStart, sizeof(permStrLen));
399 return (startPerm);
400 }
402 /* FUNCTION PURPOSE: Frees a linked list of assignment permissions
403 ***********************************************************************
404 * DESCRIPTION: Frees the memory associated with a linked list of
405 * assignment permissions extracted from a permissions
406 * assignment subgroup in a policy DTB.
407 */
408 static void policyFreeAssignmentPermissions(Rm_PolicyPermission *permissionList)
409 {
410 Rm_PolicyPermission *nextPerm;
412 while (permissionList) {
413 nextPerm = permissionList->nextPermission;
414 Rm_osalFree((void *)permissionList, sizeof(Rm_PolicyPermission));
415 permissionList = nextPerm;
416 }
417 }
419 /* FUNCTION PURPOSE: Extracts permissions from a Policy "assignment"
420 ***********************************************************************
421 * DESCRIPTION: Returns a linked list of permissions for a resource node
422 * containing an "assignment" property in the Policy DTB.
423 * Each node in the linked list will contain a valid instance
424 * name along with the permissions assigned to the instance
425 */
426 static Rm_PolicyPermission *policyGetAssignmentPermissions(Rm_PolicyAssignment *assignment,
427 int32_t *result)
428 {
429 Rm_PolicyPermission *startPerm = NULL;
430 Rm_PolicyPermission *newPerm = NULL;
431 Rm_PolicyPermission *prevPerm = NULL;
432 char *permStrStart = assignment->permissionsList;
433 char *permStrEnd;
434 uint32_t permStrLen = strlen(assignment->permissionsList) + 1;
435 uint32_t i = 0;
437 while(i < permStrLen) {
438 /* Find the first sub-permission specification and parse it. A sub-permission
439 * can be terminated by the termination character or the end of the string. */
440 if (!(permStrEnd = strchr(permStrStart, RM_POLICY_PERM_TERMINATOR))) {
441 /* Sub-permission termination character not found. The permission string
442 * end is the end of the entire permission string */
443 permStrEnd = permStrStart + strlen(permStrStart);
444 }
446 newPerm = policyParseSubPermission(permStrStart, permStrEnd, result);
448 if (*result != RM_SERVICE_PROCESSING) {
449 /* Delete the permission list that's been created thus far, return
450 * the error and NULL for the permission list */
451 policyFreeAssignmentPermissions(startPerm);
452 return(NULL);
453 }
455 if (prevPerm == NULL) {
456 startPerm = newPerm;
457 }
458 else {
459 prevPerm->nextPermission = newPerm;
460 }
462 /* Set prevPerm to the last sub-permission returned by the sub-permission parser */
463 prevPerm = newPerm;
464 while(prevPerm->nextPermission != NULL) {
465 prevPerm = prevPerm->nextPermission;
466 }
468 /* Update the number of characters parsed from the permission list and point to
469 * the start of the next sub-permission */
470 i += ((uint32_t)(permStrEnd - permStrStart + 1));
471 permStrStart = permStrEnd + 1;
472 }
474 return(startPerm);
475 }
477 /* FUNCTION PURPOSE: Validates a policy "assignment" string list
478 ***********************************************************************
479 * DESCRIPTION: Returns RM_OK if the specified Policy DTB "assignment"
480 * property specification parses okay and all the RM
481 * instances in the assignment match RM instances in the
482 * valid instances list
483 */
484 static int32_t policyValidateAssignmentPermissions(Rm_PolicyValidInstTree *root,
485 Rm_PolicyAssignment *assignmentList)
486 {
487 Rm_PolicyAssignment *assignment = assignmentList;
488 Rm_PolicyPermission *permissionList;
489 int32_t result = RM_OK;
491 while (assignment) {
492 /* Make sure assignment's permissions parse okay */
493 permissionList = policyGetAssignmentPermissions(assignment, &result);
494 if (result != RM_OK) {
495 return(result);
496 }
498 if (result = policyCheckInstances(root, permissionList) != RM_OK) {
499 policyFreeAssignmentPermissions(permissionList);
500 return(result);
501 }
503 policyFreeAssignmentPermissions(permissionList);
504 assignment = assignment->nextAssignment;
505 }
507 return (RM_OK);
508 }
510 /**********************************************************************
511 ************************ Internal Policy APIs ************************
512 **********************************************************************/
514 /* FUNCTION PURPOSE: Get a valid instace node from the valid inst tree
515 ***********************************************************************
516 * DESCRIPTION: Returns a valid instance node from the valid instance
517 * tree that matches the specified instName
518 */
519 Rm_PolicyValidInstNode *rmPolicyGetValidInstNode(Rm_PolicyValidInstTree *validInstTree, char *instName)
520 {
521 Rm_PolicyValidInstNode findNode;
523 memset((void *)&findNode, 0, sizeof(Rm_PolicyValidInstNode));
524 strncpy(findNode.name, instName, RM_NAME_MAX_CHARS);
526 return (RB_FIND(_Rm_PolicyValidInstTree, validInstTree, &findNode));
527 }
529 /* FUNCTION PURPOSE: Gets the Linux Valid instance node
530 ***********************************************************************
531 * DESCRIPTION: Returns a pointer to the valid instance node in the
532 * valid instance tree that matches the instance name
533 * reserved for resource assigned to the Linux kernel.
534 */
535 Rm_PolicyValidInstNode *rmPolicyGetLinuxInstNode(Rm_PolicyValidInstTree *validInstTree)
536 {
537 char linuxName[] = RM_ALLOCATED_TO_LINUX;
539 return (rmPolicyGetValidInstNode(validInstTree, linuxName));
540 }
542 /* FUNCTION PURPOSE: Validates resource permissions against a Policy DTB
543 ***********************************************************************
544 * DESCRIPTION: Returns TRUE if the instance name has the specified
545 * permissions for the specified resource in the Policy
546 * DTB. Otherwise, returns FALSE.
547 */
548 bool rmPolicyCheckPrivilege(Rm_PolicyCheckCfg *privilegeCfg, int32_t *result)
549 {
550 int32_t propertyOffset;
551 const char *propertyName;
552 int32_t propertyLen;
553 const void *propertyData;
554 Rm_PolicyAssignment *assignment = NULL;
555 Rm_PolicyAssignment *assignmentStart = NULL;
556 Rm_PolicyPermission *permission = NULL;
557 Rm_PolicyPermission *permissionStart = NULL;
558 uint32_t assignmentEnd;
559 uint32_t resourceEnd = privilegeCfg->resourceBase + privilegeCfg->resourceLength - 1;
560 bool foundInstance;
562 /* Get the resource's assignments */
563 propertyOffset = fdt_first_property_offset(privilegeCfg->policyDtb, privilegeCfg->resourceOffset);
564 if (propertyOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
565 while (propertyOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
566 propertyData = fdt_getprop_by_offset(privilegeCfg->policyDtb, propertyOffset, &propertyName, &propertyLen);
567 if (rmDtbUtilPolicyGetPropertyType(propertyName) == Rm_policyPropType_ASSIGNMENTS) {
568 assignment = assignmentStart = rmDtbUtilPolicyExtractAssignments(propertyData, propertyLen);
569 break;
570 }
571 propertyOffset = fdt_next_property_offset(privilegeCfg->policyDtb, propertyOffset);
572 }
573 }
575 if (assignment) {
576 while (assignment) {
577 assignmentEnd = assignment->resourceBase + assignment->resourceLength - 1;
578 foundInstance = false;
579 if (((privilegeCfg->resourceBase >= assignment->resourceBase) &&
580 (privilegeCfg->resourceBase <= assignmentEnd)) ||
581 ((privilegeCfg->resourceBase < assignment->resourceBase) &&
582 (resourceEnd > assignmentEnd)) ||
583 ((resourceEnd >= assignment->resourceBase) &&
584 (resourceEnd <= assignmentEnd))) {
586 permission = permissionStart = policyGetAssignmentPermissions(assignment, result);
587 while (permission) {
588 if ((strncmp(permission->instName, privilegeCfg->validInstNode->name, RM_NAME_MAX_CHARS) == 0) ||
589 (strncmp(permission->instName, Rm_policyAllInstances, RM_NAME_MAX_CHARS) == 0)) {
590 foundInstance = true;
592 /* Check instance's permissions */
593 if (privilegeCfg->type == Rm_policyCheck_INIT) {
594 if (!RM_policy_GET_PERM(permission->permissionBits, RM_POLICY_PERM_INIT_SHIFT)) {
595 policyFreeAssignmentPermissions(permissionStart);
596 rmDtbUtilPolicyFreeAssignments(assignmentStart);
597 return(false);
598 }
599 }
600 else if (privilegeCfg->type == Rm_policyCheck_USE) {
601 if (!RM_policy_GET_PERM(permission->permissionBits, RM_POLICY_PERM_USE_SHIFT)) {
602 policyFreeAssignmentPermissions(permissionStart);
603 rmDtbUtilPolicyFreeAssignments(assignmentStart);
604 return(false);
605 }
606 }
607 else if (privilegeCfg->type == Rm_policyCheck_EXCLUSIVE) {
608 if (!RM_policy_GET_PERM(permission->permissionBits, RM_POLICY_PERM_EXCLUSIVE_SHIFT)) {
609 policyFreeAssignmentPermissions(permissionStart);
610 rmDtbUtilPolicyFreeAssignments(assignmentStart);
611 return(false);
612 }
613 }
614 else if (privilegeCfg->type == Rm_policyCheck_SHARED_LINUX) {
615 if (!RM_policy_GET_PERM(permission->permissionBits, RM_POLICY_PERM_SHARED_LINUX_SHIFT)) {
616 policyFreeAssignmentPermissions(permissionStart);
617 rmDtbUtilPolicyFreeAssignments(assignmentStart);
618 return(false);
619 }
620 }
621 break;
622 }
623 permission = permission->nextPermission;
624 }
626 policyFreeAssignmentPermissions(permissionStart);
627 if (!foundInstance) {
628 rmDtbUtilPolicyFreeAssignments(assignmentStart);
629 return(false);
630 }
631 }
632 assignment = assignment->nextAssignment;
633 }
634 rmDtbUtilPolicyFreeAssignments(assignmentStart);
635 }
636 else {
637 return(false);
638 }
640 return(true);
641 }
643 /* FUNCTION PURPOSE: Returns resource base value according to the Policy
644 ***********************************************************************
645 * DESCRIPTION: Returns a resource base value based on the resource
646 * ranges assigned to the specified valid instance by the
647 * Policy DTB.
648 */
649 uint32_t rmPolicyGetResourceBase(void *policyDtb, Rm_PolicyValidInstNode *validInstNode,
650 int32_t resourceOffset, uint32_t allocType,
651 int32_t *result)
653 {
654 int32_t propertyOffset;
655 const char *propertyName;
656 int32_t propertyLen;
657 const void *propertyData;
658 Rm_PolicyAssignment *assignment = NULL;
659 Rm_PolicyAssignment *assignmentStart = NULL;
660 Rm_PolicyPermission *permission = NULL;
661 Rm_PolicyPermission *permissionStart = NULL;
662 uint32_t resourceBase = 0;
664 propertyOffset = fdt_first_property_offset(policyDtb, resourceOffset);
665 if (propertyOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
666 while (propertyOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
667 propertyData = fdt_getprop_by_offset(policyDtb, propertyOffset, &propertyName, &propertyLen);
668 if (rmDtbUtilPolicyGetPropertyType(propertyName) == Rm_policyPropType_ASSIGNMENTS) {
669 assignment = assignmentStart = rmDtbUtilPolicyExtractAssignments(propertyData, propertyLen);
670 break;
671 }
672 propertyOffset = fdt_next_property_offset(policyDtb, propertyOffset);
673 }
674 }
676 /* Search policy permissions for valid resource base */
677 while (assignment) {
678 permission = permissionStart = policyGetAssignmentPermissions(assignment, result);
679 while (permission) {
680 if ((strncmp(permission->instName, validInstNode->name, RM_NAME_MAX_CHARS) == 0) ||
681 (strncmp(permission->instName, Rm_policyAllInstances, RM_NAME_MAX_CHARS) == 0)) {
682 /* Check instance's permissions */
683 if (RM_policy_GET_PERM(allocType, RM_POLICY_PERM_INIT_SHIFT) &&
684 RM_policy_GET_PERM(permission->permissionBits, RM_POLICY_PERM_INIT_SHIFT)) {
685 resourceBase = assignment->resourceBase;
686 break;
687 }
688 else if (RM_policy_GET_PERM(allocType, RM_POLICY_PERM_USE_SHIFT) &&
689 RM_policy_GET_PERM(permission->permissionBits, RM_POLICY_PERM_USE_SHIFT)) {
690 resourceBase = assignment->resourceBase;
691 break;
692 }
693 }
694 permission = permission->nextPermission;
695 }
696 policyFreeAssignmentPermissions(permissionStart);
698 if (resourceBase) {
699 break;
700 }
701 else {
702 assignment = assignment->nextAssignment;
703 }
704 }
706 if (assignmentStart) {
707 rmDtbUtilPolicyFreeAssignments(assignmentStart);
708 }
710 return(resourceBase);
711 }
713 /* FUNCTION PURPOSE: Returns resource alignment value according to the Policy
714 ***********************************************************************
715 * DESCRIPTION: Returns a resource alignment value based on the resource
716 * alignment assigned to the specified valid instance by the
717 * Policy DTB.
718 */
719 uint32_t rmPolicyGetResourceAlignment(void *policyDtb, int32_t resourceOffset)
720 {
721 int32_t propertyOffset;
722 const char *propertyName;
723 int32_t propertyLen;
724 const void *propertyData;
725 Rm_ResourceValue *alignmentList;
726 uint32_t resourceAlignment = 0;
728 propertyOffset = fdt_first_property_offset(policyDtb, resourceOffset);
729 if (propertyOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
730 while (propertyOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
731 propertyData = fdt_getprop_by_offset(policyDtb, propertyOffset, &propertyName, &propertyLen);
732 if (rmDtbUtilPolicyGetPropertyType(propertyName) == Rm_policyPropType_ALLOCATION_ALIGNMENT) {
733 alignmentList = rmDtbUtilPolicyExtractResourceAlignments(propertyData, propertyLen);
734 resourceAlignment = alignmentList->value;
735 rmDtbUtilPolicyFreeResourceAlignments(alignmentList);
736 }
737 propertyOffset = fdt_next_property_offset(policyDtb, propertyOffset);
738 }
739 }
740 return(resourceAlignment);
741 }
743 /* FUNCTION PURPOSE: Get a resource's offset into a Policy
744 ***********************************************************************
745 * DESCRIPTION: Returns the location of the specified resource node
746 * within the specified Policy in the form of an offset
747 * into the DTB. The resourceName and the Policy
748 * node name must match.
749 */
750 int32_t rmPolicyGetResourceOffset(void *policyDtb, char *resourceName)
751 {
752 int32_t nodeOffset;
753 int32_t depth;
754 const char *nodeName;
756 depth = RM_DTB_UTIL_STARTING_DEPTH;
757 nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;
759 /* Find node offset for provided resource name */
760 while ((nodeOffset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) &&
761 (depth >= RM_DTB_UTIL_STARTING_DEPTH)) {
762 nodeOffset = fdt_next_node(policyDtb, nodeOffset, &depth);
763 nodeName = fdt_get_name(policyDtb, nodeOffset, NULL);
765 if (strncmp(nodeName, resourceName, RM_NAME_MAX_CHARS) == 0)
766 {
767 break;
768 }
769 }
771 if (depth < RM_DTB_UTIL_STARTING_DEPTH) {
772 /* Resource name not found */
773 nodeOffset = RM_SERVICE_DENIED_RES_DOES_NOT_EXIST;
774 }
775 return(nodeOffset);
776 }
778 /* FUNCTION PURPOSE: Validates a Policy's resource node names
779 ***********************************************************************
780 * DESCRIPTION: Returns RM_OK if all of a Policy's resource node names
781 * match a node name specified in the "valid-instances"
782 * list specified at the top of the Policy. Otherwise,
783 * returns error
784 */
785 int32_t rmPolicyValidatePolicyResourceNames(void *policyDtb, void *allocatorList)
786 {
787 Rm_Allocator *allocator = (Rm_Allocator *)allocatorList;
788 int32_t nodeOffset;
789 int32_t depth;
790 const char *nodeName;
792 depth = RM_DTB_UTIL_STARTING_DEPTH;
793 nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;
795 /* Parse DTB, verifying each resource's assignment permissions.
796 * Permissions must have correct syntax and contain valid instance names
797 * according validInstList */
798 while ((nodeOffset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) &&
799 (depth >= RM_DTB_UTIL_STARTING_DEPTH)) {
800 nodeOffset = fdt_next_node(policyDtb, nodeOffset, &depth);
801 nodeName = fdt_get_name(policyDtb, nodeOffset, NULL);
802 if (fdt_first_property_offset(policyDtb, nodeOffset) > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
803 if (rmAllocatorFind(allocator, (char *)nodeName) == NULL) {
804 /* No allocator tied to resource name */
805 return(RM_ERROR_UNKNOWN_RESOURCE_IN_POLICY);
806 }
807 }
808 }
809 return(RM_OK);
810 }
812 /* FUNCTION PURPOSE: Validates a Policy DTB
813 ***********************************************************************
814 * DESCRIPTION: Returns RM_OK if the input Policy satisfies the
815 * following conditions:
816 * a) All "assignment" permission string parse okay
817 * b) All RM instance names specified in the permission
818 * strings match an instance name in the valid instance
819 * list
820 * c) All resource node names match a resource allocator
821 */
822 int32_t rmPolicyValidatePolicy(void *policyDtb, Rm_PolicyValidInstTree *validInstTree)
823 {
824 int32_t nodeOffset;
825 int32_t propertyOffset;
826 int32_t depth;
827 const char *propertyName;
828 int32_t propertyLen;
829 const void *propertyData;
830 Rm_PolicyPropType propertyType;
831 Rm_PolicyAssignment *assignmentList;
832 int32_t result;
834 depth = RM_DTB_UTIL_STARTING_DEPTH;
835 nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;
837 /* Parse DTB, verifying each resource's assignment permissions.
838 * Permissions must have correct syntax and contain valid instance names
839 * according validInstList */
840 while ((nodeOffset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) &&
841 (depth >= RM_DTB_UTIL_STARTING_DEPTH)) {
842 nodeOffset = fdt_next_node(policyDtb, nodeOffset, &depth);
843 propertyOffset = fdt_first_property_offset(policyDtb, nodeOffset);
844 while (propertyOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
845 propertyData = fdt_getprop_by_offset(policyDtb, propertyOffset, &propertyName, &propertyLen);
846 propertyType = rmDtbUtilPolicyGetPropertyType(propertyName);
847 if (propertyType == Rm_policyPropType_ASSIGNMENTS) {
848 assignmentList = rmDtbUtilPolicyExtractAssignments(propertyData, propertyLen);
850 if ((result = policyValidateAssignmentPermissions(validInstTree, assignmentList)) != RM_OK) {
851 rmDtbUtilPolicyFreeAssignments(assignmentList);
852 return(result);
853 }
854 rmDtbUtilPolicyFreeAssignments(assignmentList);
855 }
856 else if (propertyType == Rm_policyPropType_UNKNOWN) {
857 return(RM_ERROR_UNKNOWN_POLICY_RESOURCE_PROPERTY);
858 }
859 propertyOffset = fdt_next_property_offset(policyDtb, propertyOffset);
860 }
861 }
862 return(RM_OK);
863 }
865 /* FUNCTION PURPOSE: Creates the valid instance tree for a RM instance
866 ***********************************************************************
867 * DESCRIPTION: Creates the valid instance tree for a RM instance
868 * that has been provided a global or static policy
869 * The valid instance tree is created from the
870 * "valid-instances" property at the top of the Policy.
871 * The root entry of the valid instance tree is returned.
872 */
873 Rm_PolicyValidInstTree *rmPolicyCreateValidInstTree(void *policyDtb, bool addLinux, int32_t *result)
874 {
875 int32_t validInstOffset;
876 const char *validInstName = NULL;
877 int32_t validInstLen;
878 const void *validInstData = NULL;
879 Rm_PolicyPropType propertyType;
880 Rm_PolicyValidInst *validInstList = NULL;
881 Rm_PolicyValidInstTree *rootEntry = NULL;
882 Rm_PolicyValidInstNode *newNode = NULL;
883 char linuxName[] = RM_ALLOCATED_TO_LINUX;
885 /* Valid instance list must be first and only property in the root node of
886 * the policyDtb */
887 validInstOffset = fdt_first_property_offset(policyDtb, RM_DTB_UTIL_STARTING_NODE_OFFSET);
888 if (validInstOffset < -FDT_ERR_NOTFOUND) {
889 *result = validInstOffset;
890 return (NULL);
891 }
892 else if (validInstOffset == -FDT_ERR_NOTFOUND) {
893 *result = RM_ERROR_NO_VALID_INST_IN_POLICY;
894 return (NULL);
895 }
896 validInstData = fdt_getprop_by_offset(policyDtb, validInstOffset, &validInstName, &validInstLen);
897 propertyType = rmDtbUtilPolicyGetPropertyType(validInstName);
898 if (propertyType != Rm_policyPropType_VALID_INSTANCES) {
899 *result = RM_ERROR_NO_VALID_INST_IN_POLICY;
900 return (NULL);
901 }
903 if (!(validInstList = rmDtbUtilPolicyExtractValidInstances(validInstData, validInstLen, result))) {
904 return (NULL);
905 }
907 /* Create the tree */
908 rootEntry = Rm_osalMalloc(sizeof(Rm_PolicyValidInstTree));
909 RB_INIT(rootEntry);
911 while (validInstList) {
912 newNode = rmPolicyValidInstNodeNew(validInstList->instName);
913 RB_INSERT(_Rm_PolicyValidInstTree, rootEntry, newNode);
915 validInstList = validInstList->nextValidInst;
916 }
918 /* Add the Linux kernel node */
919 if (addLinux) {
920 newNode = rmPolicyValidInstNodeNew(linuxName);
921 RB_INSERT(_Rm_PolicyValidInstTree, rootEntry, newNode);
922 }
924 *result = RM_OK;
925 return (rootEntry);
926 }
928 /* FUNCTION PURPOSE: Deletes a valid instance tree
929 ***********************************************************************
930 * DESCRIPTION: Frees all memory associated with a Policy valid
931 * instance tree.
932 */
933 void rmPolicyFreeValidInstTree(Rm_PolicyValidInstTree *validInstTree)
934 {
935 Rm_PolicyValidInstNode *node;
936 Rm_PolicyValidInstNode *nextNode;
938 for (node = RB_MIN(_Rm_PolicyValidInstTree, validInstTree); node != NULL; node = nextNode) {
939 nextNode = RB_NEXT(_Rm_PolicyValidInstTree, validInstTree, node);
940 RB_REMOVE(_Rm_PolicyValidInstTree, validInstTree, node);
941 rmPolicyValidInstNodeFree(node);
942 }
943 if (RB_MIN(_Rm_PolicyValidInstTree, validInstTree) == NULL) {
944 /* No more valid instance nodes in tree */
945 Rm_osalFree((void *)validInstTree, sizeof(Rm_PolicyValidInstTree));
946 }
947 }