1 /**
2 * @file rm_policy.c
3 *
4 * @brief
5 * Resource Manager Policy source.
6 *
7 * \par
8 * ============================================================================
9 * @n (C) Copyright 2012-2015, Texas Instruments, Inc.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 *
15 * Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 *
18 * Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the
21 * distribution.
22 *
23 * Neither the name of Texas Instruments Incorporated nor the names of
24 * its contributors may be used to endorse or promote products derived
25 * from this software without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
31 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
32 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
33 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
37 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 *
39 * \par
40 */
42 /* Standard includes */
43 #include <ctype.h>
45 /* RM external API includes */
46 #include <ti/drv/rm/rm.h>
48 /* RM internal API includes */
49 #include <ti/drv/rm/include/rm_internal.h>
50 #include <ti/drv/rm/include/rm_loc.h>
51 #include <ti/drv/rm/include/rm_allocatorloc.h>
52 #include <ti/drv/rm/include/rm_policyloc.h>
53 #include <ti/drv/rm/include/rm_dtb_utilloc.h>
55 /* RM LIBFDT includes */
56 #include <ti/drv/rm/util/libfdt/libfdt.h>
58 /* Tree algorithm includes */
59 #include <ti/drv/rm/util/tree.h>
61 /* RM OSAL layer */
62 #include <rm_osal.h>
64 /**********************************************************************
65 *********************** Policy Globals *******************************
66 **********************************************************************/
68 /* Character used in policies to specify all RM instances receive
69 * the defined permissions for a resource node */
70 const char Rm_policyGlobalInst[] = "*";
72 /**********************************************************************
73 ******************** Local Policy Functions **************************
74 **********************************************************************/
76 /* FUNCTION PURPOSE: Parses a permissions subgroup
77 ***********************************************************************
78 * DESCRIPTION: Returns a linked list of policy permissions defining
79 * which RM instance referenced in the permissions subgroup
80 * get which permissions. Returns NULL if any syntax
81 * errors are encountered during the parsing. The error
82 * is returned via the result pointer parameter.
83 */
84 static Rm_PolicyPermission *policyParseSubPermission(char *permStrStart,
85 char *permStrEnd,
86 int32_t *result)
87 {
88 Rm_PolicyPermission *startPerm = NULL;
89 Rm_PolicyPermission *newPerm = NULL;
90 Rm_PolicyPermission *prevPerm = NULL;
91 Rm_PolicyPermission *nextPerm = NULL;
92 char *permStrPtr = NULL;
93 char *subgroupStart = NULL;
94 char *subgroupEnd = NULL;
95 uint32_t permStrLen = (uint32_t)(permStrEnd - permStrStart + 1);
96 char instNameTemp[RM_NAME_MAX_CHARS];
97 uint32_t instNameIndex;
98 int foundInstName;
99 int instNameComplete;
100 int assignmentLeft;
101 int assignmentRight;
103 /* Create a local copy of the sub-permission string */
104 permStrPtr = Rm_osalMalloc(permStrLen);
105 rm_strncpy(permStrPtr, permStrStart, permStrLen);
107 permStrStart = permStrPtr;
108 permStrEnd = permStrPtr + strlen(permStrPtr);
110 /* Find the beginning and end of the sub-permission instance group */
111 subgroupStart = strchr(permStrStart, RM_POLICY_PERM_SUBGROUP_START);
112 subgroupEnd = strchr(permStrStart, RM_POLICY_PERM_SUBGROUP_END);
114 if ((!subgroupStart) || (!subgroupEnd) || (subgroupStart > subgroupEnd) ||
115 ((subgroupStart != strrchr(permStrStart,
116 RM_POLICY_PERM_SUBGROUP_START)) &&
117 (subgroupEnd != strrchr(permStrStart,
118 RM_POLICY_PERM_SUBGROUP_END)))) {
119 /* Free the memory associated with the temp string and return an
120 * error if:
121 * a) Could not find the instance group start
122 * b) Could not find the instance group end
123 * c) Subgroup start and end are out of order
124 * d) There is more than one instance subgroup specified in the string.
125 * There should only be one subgroup per sub-permission string */
126 *result = RM_ERROR_PERM_STR_TOO_MANY_INST_GROUPS;
127 goto parseError;
128 }
130 /* Create a permission entry for each instance specified in the instance group.
131 * Instances names are separated by one or more spaces. */
132 permStrPtr = subgroupStart + 1;
133 instNameIndex = 0;
134 foundInstName = RM_FALSE;
135 instNameComplete = RM_FALSE;
136 while (permStrPtr <= subgroupEnd) {
137 if ((isspace(*permStrPtr) ||
138 (*permStrPtr == RM_POLICY_PERM_SUBGROUP_END))
139 && foundInstName) {
140 /* First space encountered after copying an instance name. This
141 * terminates the instance name. All other space characters are
142 * ignored. */
143 instNameTemp[instNameIndex] = '\0';
144 instNameComplete = RM_TRUE;
145 } else {
146 if (!foundInstName) {
147 /* First non-whitespace character encountered is the start of an
148 * instance name */
149 foundInstName = RM_TRUE;
150 }
152 /* Copy the character into the temporary instance name string */
153 instNameTemp[instNameIndex++] = *permStrPtr;
154 }
156 if (instNameComplete) {
157 newPerm = Rm_osalMalloc(sizeof(*newPerm));
158 memset((void *)newPerm, 0, sizeof(*newPerm));
160 rm_strncpy(newPerm->instName, instNameTemp, RM_NAME_MAX_CHARS);
161 newPerm->nextPermission = NULL;
163 if (prevPerm == NULL) {
164 /* Save the first instance so it can be returned */
165 startPerm = newPerm;
166 } else {
167 prevPerm->nextPermission = newPerm;
168 }
169 prevPerm = newPerm;
171 instNameComplete = RM_FALSE;
172 instNameIndex = 0;
173 foundInstName = RM_FALSE;
174 }
176 if (instNameIndex == RM_NAME_MAX_CHARS) {
177 /* Instance name is longer than max length */
178 *result = RM_ERROR_INST_NAME_IN_ASSIGNMENT_TOO_LONG;
179 goto parseError;
180 }
182 permStrPtr++;
183 }
185 /* Fill in the permissions for each instance name */
187 /* Look on left of instance group for permission assignments. */
188 permStrPtr = subgroupStart - 1;
189 assignmentLeft = RM_FALSE;
190 while (permStrPtr >= permStrStart)
191 {
192 if (*permStrPtr == RM_POLICY_PERM_ASSIGNMENT) {
193 if (assignmentLeft) {
194 /* Assignment character has been found more than once. This
195 * is a syntax error. Free the permission list and the
196 * temporary string and return. */
197 *result = RM_ERROR_PERM_STR_TOO_MANY_ASSIGN_CHARS;
198 goto parseError;
199 } else {
200 assignmentLeft = RM_TRUE;
201 }
202 } else if (!isspace(*permStrPtr)) {
203 if (assignmentLeft) {
204 if ((*permStrPtr == RM_POLICY_PERM_INIT_LOWER) ||
205 (*permStrPtr == RM_POLICY_PERM_INIT_UPPER)) {
206 newPerm = startPerm;
207 while (newPerm) {
208 Rm_PolicyPermBits *pBits = &(newPerm->permissionBits);
209 RM_policy_PERM_SET(pBits, 0, 0,
210 RM_POLICY_PERM_INIT_SHIFT, 1);
211 newPerm = newPerm->nextPermission;
212 }
213 } else if ((*permStrPtr == RM_POLICY_PERM_USE_LOWER) ||
214 (*permStrPtr == RM_POLICY_PERM_USE_UPPER)) {
215 newPerm = startPerm;
216 while (newPerm) {
217 Rm_PolicyPermBits *pBits = &(newPerm->permissionBits);
218 RM_policy_PERM_SET(pBits, 0, 0,
219 RM_POLICY_PERM_USE_SHIFT, 1);
220 newPerm = newPerm->nextPermission;
221 }
222 } else if ((*permStrPtr == RM_POLICY_PERM_EXCLUSIVE_LOWER) ||
223 (*permStrPtr == RM_POLICY_PERM_EXCLUSIVE_UPPER)) {
224 newPerm = startPerm;
225 while (newPerm) {
226 Rm_PolicyPermBits *pBits = &(newPerm->permissionBits);
227 RM_policy_PERM_SET(pBits, 0, 0,
228 RM_POLICY_PERM_EXCLUSIVE_SHIFT, 1);
229 newPerm = newPerm->nextPermission;
230 }
231 } else if ((*permStrPtr == RM_POLICY_PERM_SHARED_LINUX_LOWER) ||
232 (*permStrPtr == RM_POLICY_PERM_SHARED_LINUX_UPPER)) {
233 newPerm = startPerm;
234 while (newPerm) {
235 Rm_PolicyPermBits *pBits = &(newPerm->permissionBits);
236 RM_policy_PERM_SET(pBits, 0, 0,
237 RM_POLICY_PERM_SHARED_LINUX_SHIFT,
238 1);
239 newPerm = newPerm->nextPermission;
240 }
241 } else if ((*permStrPtr ==
242 RM_POLICY_PERM_UNSPEC_EXCLUSION_LOWER) ||
243 (*permStrPtr ==
244 RM_POLICY_PERM_UNSPEC_EXCLUSION_UPPER)) {
245 newPerm = startPerm;
246 while (newPerm) {
247 Rm_PolicyPermBits *pBits = &(newPerm->permissionBits);
248 RM_policy_PERM_SET(pBits, 0, 0,
249 RM_POLICY_PERM_UNSPEC_EXCLUSION_SHIFT, 1);
250 newPerm = newPerm->nextPermission;
251 }
252 } else {
253 /* Invalid permission character. This is a syntax error.
254 * Free the permission list and the temporary string
255 * and return. */
256 *result = RM_ERROR_PERM_STR_INVALID_CHAR;
257 goto parseError;
258 }
259 } else {
260 /* Character found without the assignment character being found.
261 * This is a syntax error. Free the permission list and the
262 * temporary string and return. */
263 *result = RM_ERROR_PERM_CHAR_WITHOUT_ASSIGN_CHAR;
264 goto parseError;
265 }
266 }
267 permStrPtr--;
268 }
270 /* Look on right of instance group for permission assignments. */
271 permStrPtr = subgroupEnd + 1;
272 assignmentRight = RM_FALSE;
273 while (permStrPtr < permStrEnd) {
274 if (assignmentLeft && (!isspace(*permStrPtr))) {
275 /* There should be nothing but spaces on right if assignment was
276 * already found on left */
277 *result = RM_ERROR_INVALID_PERMS_CHAR_ON_RIGHT;
278 goto parseError;
279 }
281 if (*permStrPtr == RM_POLICY_PERM_ASSIGNMENT) {
282 if (assignmentRight) {
283 /* Assignment character has been found more than once. This is
284 * a syntax error. Free the permission list and the temporary
285 * string and return. */
286 *result = RM_ERROR_PERM_STR_TOO_MANY_ASSIGN_CHARS;
287 goto parseError;
288 } else {
289 assignmentRight = RM_TRUE;
290 }
291 } else if (!isspace(*permStrPtr)) {
292 if (assignmentRight) {
293 if ((*permStrPtr == RM_POLICY_PERM_INIT_LOWER) ||
294 (*permStrPtr == RM_POLICY_PERM_INIT_UPPER)) {
295 newPerm = startPerm;
296 while (newPerm) {
297 Rm_PolicyPermBits *pBits = &(newPerm->permissionBits);
298 RM_policy_PERM_SET(pBits, 0, 0,
299 RM_POLICY_PERM_INIT_SHIFT, 1);
300 newPerm = newPerm->nextPermission;
301 }
302 } else if ((*permStrPtr == RM_POLICY_PERM_USE_LOWER) ||
303 (*permStrPtr == RM_POLICY_PERM_USE_UPPER)) {
304 newPerm = startPerm;
305 while (newPerm) {
306 Rm_PolicyPermBits *pBits = &(newPerm->permissionBits);
307 RM_policy_PERM_SET(pBits, 0, 0,
308 RM_POLICY_PERM_USE_SHIFT, 1);
309 newPerm = newPerm->nextPermission;
310 }
311 } else if ((*permStrPtr == RM_POLICY_PERM_EXCLUSIVE_LOWER) ||
312 (*permStrPtr == RM_POLICY_PERM_EXCLUSIVE_UPPER)) {
313 newPerm = startPerm;
314 while (newPerm) {
315 Rm_PolicyPermBits *pBits = &(newPerm->permissionBits);
316 RM_policy_PERM_SET(pBits, 0, 0,
317 RM_POLICY_PERM_EXCLUSIVE_SHIFT, 1);
318 newPerm = newPerm->nextPermission;
319 }
320 } else if ((*permStrPtr == RM_POLICY_PERM_SHARED_LINUX_LOWER) ||
321 (*permStrPtr == RM_POLICY_PERM_SHARED_LINUX_UPPER)) {
322 newPerm = startPerm;
323 while (newPerm) {
324 Rm_PolicyPermBits *pBits = &(newPerm->permissionBits);
325 RM_policy_PERM_SET(pBits, 0, 0,
326 RM_POLICY_PERM_SHARED_LINUX_SHIFT,
327 1);
328 newPerm = newPerm->nextPermission;
329 }
330 } else if ((*permStrPtr ==
331 RM_POLICY_PERM_UNSPEC_EXCLUSION_LOWER) ||
332 (*permStrPtr ==
333 RM_POLICY_PERM_UNSPEC_EXCLUSION_UPPER)) {
334 newPerm = startPerm;
335 while (newPerm) {
336 Rm_PolicyPermBits *pBits = &(newPerm->permissionBits);
337 RM_policy_PERM_SET(pBits, 0, 0,
338 RM_POLICY_PERM_UNSPEC_EXCLUSION_SHIFT, 1);
339 newPerm = newPerm->nextPermission;
340 }
341 } else {
342 /* Invalid permission character. This is a syntax error.
343 * Free the permission list and the temporary string
344 * and return. */
345 *result = RM_ERROR_PERM_STR_INVALID_CHAR;
346 goto parseError;
347 }
348 } else {
349 /* Character found without the assignment character being found.
350 * This is a syntax error. Free the permission list and the
351 * temporary string and return. */
352 *result = RM_ERROR_PERM_STR_TOO_MANY_ASSIGN_CHARS;
353 goto parseError;
354 }
355 }
356 permStrPtr++;
357 }
359 Rm_osalFree((void *)permStrStart, permStrLen);
360 *result = RM_OK;
361 return (startPerm);
363 parseError:
364 while (startPerm) {
365 nextPerm = startPerm->nextPermission;
366 Rm_osalFree((void *)startPerm, sizeof(Rm_PolicyPermission));
367 startPerm = nextPerm;
368 }
369 Rm_osalFree((void *)permStrStart, permStrLen);
370 return(NULL);
371 }
373 /* FUNCTION PURPOSE: Frees a linked list of assignment permissions
374 ***********************************************************************
375 * DESCRIPTION: Frees the memory associated with a linked list of
376 * assignment permissions extracted from a permissions
377 * assignment subgroup in a policy DTB.
378 */
379 static void policyFreeAssignmentPermissions(Rm_PolicyPermission *permissionList)
380 {
381 Rm_PolicyPermission *nextPerm;
383 while (permissionList) {
384 nextPerm = permissionList->nextPermission;
385 Rm_osalFree((void *)permissionList, sizeof(Rm_PolicyPermission));
386 permissionList = nextPerm;
387 }
388 }
390 /* FUNCTION PURPOSE: Extracts permissions from a Policy "assignment"
391 ***********************************************************************
392 * DESCRIPTION: Returns a linked list of permissions for a resource node
393 * containing an "assignment" property in the Policy DTB.
394 * Each node in the linked list will contain a valid instance
395 * name along with the permissions assigned to the instance
396 */
397 static Rm_PolicyPermission *policyGetAssignmentPermissions(Rm_PolicyAssignment *assignment,
398 int32_t *result)
399 {
400 Rm_PolicyPermission *startPerm = NULL;
401 Rm_PolicyPermission *newPerm = NULL;
402 Rm_PolicyPermission *prevPerm = NULL;
403 char *permStrStart = assignment->permissionsList;
404 char *permStrEnd;
405 uint32_t permStrLen = strlen(assignment->permissionsList) + 1;
406 uint32_t i = 0;
408 *result = RM_OK;
410 while(i < permStrLen) {
411 /* Find the first sub-permission specification and parse it. A
412 * sub-permission can be terminated by the termination character or the
413 * end of the string. */
414 if (!(permStrEnd = strchr(permStrStart, RM_POLICY_PERM_TERMINATOR))) {
415 /* Sub-permission termination character not found. The permission
416 * string end is the end of the entire permission string */
417 permStrEnd = permStrStart + strlen(permStrStart);
418 }
420 newPerm = policyParseSubPermission(permStrStart, permStrEnd, result);
422 if (*result != RM_OK) {
423 /* Delete the permission list that's been created thus far, return
424 * the error and NULL for the permission list */
425 policyFreeAssignmentPermissions(startPerm);
426 return(NULL);
427 }
429 if (prevPerm == NULL) {
430 startPerm = newPerm;
431 } else {
432 prevPerm->nextPermission = newPerm;
433 }
435 /* Set prevPerm to the last sub-permission returned by the
436 * sub-permission parser */
437 prevPerm = newPerm;
438 while(prevPerm->nextPermission != NULL) {
439 prevPerm = prevPerm->nextPermission;
440 }
442 /* Update the number of characters parsed from the permission list and
443 * point to the start of the next sub-permission */
444 i += ((uint32_t)(permStrEnd - permStrStart + 1));
445 permStrStart = permStrEnd + 1;
446 }
448 return(startPerm);
449 }
451 /* FUNCTION PURPOSE: Returns number of bytes needed to store permissions
452 ***********************************************************************
453 * DESCRIPTION: Calculates and returns the number of bytes needed to store
454 * permissions for all valid instances. Words are packed
455 * with permissions for as many instances as can fit
456 */
457 static uint32_t policyGetPermBufSize(uint32_t maxValidInst)
458 {
459 uint32_t instPerWord;
460 uint32_t numWords;
461 uint32_t totalBytes = 0;
463 instPerWord = RM_policy_PERM_INST_PER_WORD;
464 /* Round up */
465 numWords = (maxValidInst + instPerWord - 1) / instPerWord;
467 totalBytes = sizeof(Rm_PolicyPermBits) * numWords;
468 return(totalBytes);
469 }
471 /* FUNCTION PURPOSE: Stores policy permissions in a policy tree node
472 ***********************************************************************
473 * DESCRIPTION: Parses permissions and stores them in a word array in a
474 * compacted format. The array is attached to the resource's
475 * policy tree node.
476 */
477 static int32_t policyStorePermissions(Rm_Inst *rmInst, Rm_PolicyNode *polNode,
478 Rm_PolicyPermission *extractedPerms)
479 {
480 Rm_PolicyValidInstNode *vInst = NULL;
481 uint32_t instIdx;
482 uint32_t wordIndex;
483 uint32_t wordOffset;
484 int32_t retVal = RM_OK;
486 while (extractedPerms) {
487 if (!strncmp(extractedPerms->instName, Rm_policyGlobalInst,
488 RM_NAME_MAX_CHARS)) {
489 instIdx = RM_POLICY_GLOBAL_PERM_INDEX;
490 } else if ((vInst = rmPolicyGetValidInstNode((Rm_Handle)rmInst,
491 extractedPerms->instName))) {
492 instIdx = vInst->instIdx;
493 } else {
494 retVal = RM_ERROR_PERM_STR_INST_NOT_VALID;
495 goto errorExit;
496 }
498 /* Calculate word index into policy node's permission array
499 * for the instance index */
500 wordIndex = RM_policy_PERM_INDEX(instIdx);
501 wordOffset = RM_policy_PERM_OFFSET(instIdx);
503 polNode->perms[wordIndex] |= ((extractedPerms->permissionBits &
504 RM_policy_PERM_FULL_MASK) << wordOffset);
506 extractedPerms = extractedPerms->nextPermission;
507 }
509 errorExit:
510 return(retVal);
511 }
513 /* FUNCTION PURPOSE: Returns resource's allocation alignment from policy
514 ***********************************************************************
515 * DESCRIPTION: Parses the policy DTB to find and return a resource's
516 * allocation alignment.
517 */
518 static uint32_t policyGetDtbAllocAlign(void *policyDtb, int32_t resourceOffset)
519 {
520 int32_t offset;
521 const char *name;
522 int32_t len;
523 const void *data;
524 Rm_ResourceValue *alignList = NULL;
525 uint32_t align = 0;
527 offset = fdt_first_property_offset(policyDtb, resourceOffset);
528 while (offset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
529 data = fdt_getprop_by_offset(policyDtb, offset, &name, &len);
530 if (rmDtbUtilPolicyGetPropertyType(name) ==
531 Rm_policyPropType_ALLOCATION_ALIGNMENT) {
532 alignList = rmDtbUtilPolicyExtractResourceAlignments(data, len);
533 align = alignList->value;
534 break;
535 }
536 offset = fdt_next_property_offset(policyDtb, offset);
537 }
539 if (alignList) {
540 rmDtbUtilPolicyFreeResourceAlignments(alignList);
541 }
543 if (align == 0) {
544 align = 1;
545 }
546 return(align);
547 }
549 /* FUNCTION PURPOSE: Returns resource CD allocation size defined in policy
550 ***********************************************************************
551 * DESCRIPTION: Parses the policy DTB to find and return a resource's
552 * allocation size.
553 */
554 static uint32_t policyGetDtbCdAllocSize(void *policyDtb, int32_t resourceOffset)
555 {
556 int32_t offset;
557 const char *name;
558 int32_t len;
559 const void *data;
560 Rm_ResourceValue *allocSizeList = NULL;
561 uint32_t allocSize = 0;
563 offset = fdt_first_property_offset(policyDtb, resourceOffset);
564 while (offset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
565 data = fdt_getprop_by_offset(policyDtb, offset, &name, &len);
566 if (rmDtbUtilPolicyGetPropertyType(name) ==
567 Rm_policyPropType_CD_ALLOCATION_SIZE) {
568 allocSizeList = rmDtbUtilPolicyExtractCdAllocationSizes(data, len);
569 allocSize = allocSizeList->value;
570 break;
571 }
572 offset = fdt_next_property_offset(policyDtb, offset);
573 }
575 if (allocSizeList) {
576 rmDtbUtilPolicyFreeCdAllocationSizes(allocSizeList);
577 }
578 return(allocSize);
579 }
581 /* FUNCTION PURPOSE: Get a resource's offset into a policy
582 ***********************************************************************
583 * DESCRIPTION: Returns the location of the specified resource node
584 * within the specified Policy in the form of an offset
585 * into the DTB. The resourceName and the Policy
586 * node name must match.
587 */
588 static int32_t policyGetDtbResourceOffset(void *policyDtb,
589 const char *resourceName)
590 {
591 int32_t nodeOffset;
592 int32_t depth;
593 const char *nodeName;
595 if (policyDtb) {
596 depth = RM_DTB_UTIL_STARTING_DEPTH;
597 nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;
599 /* Find node offset for provided resource name */
600 while (nodeOffset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) {
601 nodeOffset = fdt_next_node(policyDtb, nodeOffset, &depth);
602 if (depth < RM_DTB_UTIL_STARTING_DEPTH) {
603 /* Resource name not found */
604 nodeOffset = RM_ERROR_RES_DOES_NOT_EXIST_IN_POLICY;
605 break;
606 } else {
607 nodeName = fdt_get_name(policyDtb, nodeOffset, NULL);
608 if (strncmp(nodeName, resourceName, RM_NAME_MAX_CHARS) == 0) {
609 break;
610 }
611 }
612 }
613 } else {
614 nodeOffset = RM_ERROR_INSTANCE_HAS_NO_POLICY;
615 }
616 return(nodeOffset);
617 }
619 /**********************************************************************
620 ************************ Internal Policy APIs ************************
621 **********************************************************************/
623 /* FUNCTION PURPOSE: Get a valid instace node from the valid inst tree
624 ***********************************************************************
625 * DESCRIPTION: Returns a valid instance node from the valid instance
626 * tree that matches the specified instName
627 */
628 Rm_PolicyValidInstNode *rmPolicyGetValidInstNode(Rm_Handle rmHandle,
629 const char *instName)
630 {
631 Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
632 Rm_PolicyValidInstTree *treeRoot = rmInst->validInstTree;
633 Rm_PolicyValidInstNode findNode;
635 rm_strncpy(findNode.name, instName, RM_NAME_MAX_CHARS);
636 return(RB_FIND(_Rm_PolicyValidInstTree, treeRoot, &findNode));
637 }
639 /* FUNCTION PURPOSE: Gets the Linux Valid instance node
640 ***********************************************************************
641 * DESCRIPTION: Returns a pointer to the valid instance node in the
642 * valid instance tree that matches the instance name
643 * reserved for resource assigned to the Linux kernel.
644 */
645 Rm_PolicyValidInstNode *rmPolicyGetLinuxInstNode(Rm_Handle rmHandle)
646 {
647 const char linuxName[] = RM_ALLOCATED_TO_LINUX;
649 return(rmPolicyGetValidInstNode(rmHandle, linuxName));
650 }
652 /* FUNCTION PURPOSE: Validates resource permissions against a Policy DTB
653 ***********************************************************************
654 * DESCRIPTION: Returns TRUE if the instance name has the specified
655 * permissions for the specified resource in the Policy
656 * DTB. Otherwise, returns FALSE.
657 */
658 int32_t rmPolicyCheckPrivilege(Rm_PolicyCheckCfg *privilegeCfg)
659 {
660 uint32_t permShift;
661 uint32_t globPermIdx;
662 uint32_t globPermOffset;
663 uint32_t instPermIdx;
664 uint32_t instPermOffset;
665 Rm_PolicyNode findNode;
666 Rm_PolicyNode *matchNode = NULL;
667 uint32_t findEnd;
668 uint32_t matchEnd;
669 int32_t isApproved = RM_FALSE;
671 switch (privilegeCfg->type) {
672 case Rm_policyCheck_INIT:
673 permShift = RM_POLICY_PERM_INIT_SHIFT;
674 break;
675 case Rm_policyCheck_USE:
676 permShift = RM_POLICY_PERM_USE_SHIFT;
677 break;
678 case Rm_policyCheck_EXCLUSIVE:
679 permShift = RM_POLICY_PERM_EXCLUSIVE_SHIFT;
680 break;
681 case Rm_policyCheck_SHARED_LINUX:
682 permShift = RM_POLICY_PERM_SHARED_LINUX_SHIFT;
683 break;
684 case Rm_policyCheck_UNSPEC_EXCLUSION:
685 permShift = RM_POLICY_PERM_UNSPEC_EXCLUSION_SHIFT;
686 break;
687 default:
688 return(isApproved);
689 }
691 /* Calculate the word indices and offsets for the global permissions and
692 * the specific instance */
693 globPermIdx = RM_policy_PERM_INDEX(RM_POLICY_GLOBAL_PERM_INDEX);
694 globPermOffset = RM_policy_PERM_OFFSET(RM_POLICY_GLOBAL_PERM_INDEX);
695 instPermIdx = RM_policy_PERM_INDEX(privilegeCfg->validInstNode->instIdx);
696 instPermOffset = RM_policy_PERM_OFFSET(privilegeCfg->validInstNode->instIdx);
698 memset((void *)&findNode, 0, sizeof(findNode));
699 findNode.base = privilegeCfg->resourceBase;
700 findNode.len = privilegeCfg->resourceLength;
701 /* Get first matching node. */
702 matchNode = RB_FIND(_Rm_AllocatorPolicyTree, privilegeCfg->polTree,
703 &findNode);
704 if (matchNode) {
705 /* Request range may not be completely contained within the first
706 * matching node. Find furthest left matching node for the request
707 * range */
708 while (findNode.base < matchNode->base) {
709 matchNode = RB_PREV(_Rm_AllocatorPolicyTree,
710 privilegeCfg->polTree, matchNode);
711 }
712 }
714 /* Check permissions across all policy nodes which the request range
715 * spans. Assume approved until denial found */
716 isApproved = RM_TRUE;
717 while (matchNode) {
718 if (privilegeCfg->negCheck) {
719 /* Not approved if any matching node is assigned an exclusion
720 * permission */
721 if ((RM_policy_PERM_GET(matchNode->perms, globPermIdx,
722 globPermOffset, permShift)) ||
723 (RM_policy_PERM_GET(matchNode->perms, instPermIdx,
724 instPermOffset, permShift))) {
725 isApproved = RM_FALSE;
726 break;
727 }
728 } else {
729 /* Not approved if any matching node does not have permission */
730 if ((!RM_policy_PERM_GET(matchNode->perms, globPermIdx,
731 globPermOffset, permShift)) &&
732 (!RM_policy_PERM_GET(matchNode->perms, instPermIdx,
733 instPermOffset, permShift))) {
734 isApproved = RM_FALSE;
735 break;
736 }
737 }
739 matchEnd = matchNode->base + matchNode->len - 1;
740 findEnd = findNode.base + findNode.len - 1;
742 /* Check node to right if request range spans matching node to right */
743 if (findEnd > matchEnd) {
744 matchNode = RB_NEXT(_Rm_AllocatorPolicyTree, privilegeCfg->polTree,
745 matchNode);
746 if (matchNode == NULL) {
747 /* Request range outspans actual resource range */
748 isApproved = RM_FALSE;
749 }
750 } else {
751 break;
752 }
753 }
755 return(isApproved);
756 }
758 /* FUNCTION PURPOSE: Returns resource base value according to the Policy
759 ***********************************************************************
760 * DESCRIPTION: Returns a resource base value based on the resource
761 * ranges assigned to the specified valid instance by the
762 * Policy DTB.
763 */
764 int32_t rmPolicyGetResourceBase(Rm_PolicyTree *policyTree,
765 Rm_PolicyValidInstNode *validInstNode,
766 Rm_PolicyCheckType checkType,
767 int32_t *resBase)
768 {
769 uint32_t permShift = RM_POLICY_PERM_INIT_SHIFT;
770 uint32_t globPermIdx;
771 uint32_t globPermOffset;
772 uint32_t instPermIdx;
773 uint32_t instPermOffset;
774 Rm_PolicyNode *polNode;
776 *resBase = RM_RESOURCE_BASE_UNSPECIFIED;
778 if (checkType == Rm_policyCheck_INIT) {
779 permShift = RM_POLICY_PERM_INIT_SHIFT;
780 } else if (checkType == Rm_policyCheck_USE) {
781 permShift = RM_POLICY_PERM_USE_SHIFT;
782 } else {
783 return(RM_ERROR_INVALID_SERVICE_TYPE);
784 }
786 /* Calculate the word indices and offsets for the global permissions and
787 * the specific instance */
788 globPermIdx = RM_policy_PERM_INDEX(RM_POLICY_GLOBAL_PERM_INDEX);
789 globPermOffset = RM_policy_PERM_OFFSET(RM_POLICY_GLOBAL_PERM_INDEX);
790 instPermIdx = RM_policy_PERM_INDEX(validInstNode->instIdx);
791 instPermOffset = RM_policy_PERM_OFFSET(validInstNode->instIdx);
793 RB_FOREACH(polNode, _Rm_AllocatorPolicyTree, policyTree) {
794 if (RM_policy_PERM_GET(polNode->perms, globPermIdx, globPermOffset,
795 permShift) ||
796 RM_policy_PERM_GET(polNode->perms, instPermIdx, instPermOffset,
797 permShift)) {
798 *resBase = polNode->base;
799 break;
800 }
801 }
803 if (*resBase == RM_RESOURCE_BASE_UNSPECIFIED) {
804 return(RM_SERVICE_DENIED_RES_ALLOC_REQS_NOT_MET);
805 }
807 return(RM_OK);
808 }
810 /* FUNCTION PURPOSE: Returns resource's allocation alignment
811 ***********************************************************************
812 * DESCRIPTION: Returns a resource's allocation alignment.
813 */
814 uint32_t rmPolicyGetAllocAlign(Rm_PolicyTree *policyTree)
815 {
816 Rm_PolicyNode *node = NULL;
817 uint32_t align = 1;
819 /* Resource's alignment is global at the moment so all policy tree nodes
820 * store the same value. Just get the min node and return the allocation
821 * alignment from it */
822 node = RB_MIN(_Rm_AllocatorPolicyTree, policyTree);
823 if (node) {
824 align = node->allocAlign;
825 }
827 return(align);
828 }
830 /* FUNCTION PURPOSE: Returns resource's CD allocation size
831 ***********************************************************************
832 * DESCRIPTION: Returns a resource's CD allocation size.
833 */
834 uint32_t rmPolicyGetCdAllocSize(Rm_PolicyTree *policyTree)
835 {
836 Rm_PolicyNode *node = NULL;
837 uint32_t allocSize = 0;
839 /* Resource's CD allocation size is global at the moment so all policy
840 * tree nodes store the same value. Just get the min node and return
841 * allocation size from it */
842 node = RB_MIN(_Rm_AllocatorPolicyTree, policyTree);
843 if (node) {
844 allocSize = node->cdAllocSize;
845 }
847 return(allocSize);
848 }
850 /* FUNCTION PURPOSE: Initializes the valid instance tree for a RM instance
851 ***********************************************************************
852 * DESCRIPTION: Creates the valid instance tree for a RM instance
853 * that has been provided a global or static policy
854 * The valid instance tree is created from the
855 * "valid-instances" property at the top of the Policy.
856 * The root entry of the valid instance tree is returned.
857 */
858 Rm_PolicyValidInstTree *rmPolicyVInstTreeInit(Rm_Handle rmHandle,
859 void *policyDtb,
860 int addLinux,
861 int32_t *result)
862 {
863 Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
864 int32_t validInstOffset;
865 const char *validInstName = NULL;
866 int32_t validInstLen;
867 const void *validInstData = NULL;
868 Rm_PolicyPropType propertyType;
869 Rm_PolicyValidInst *vInstListStart = NULL;
870 Rm_PolicyValidInst *validInstList = NULL;
871 Rm_PolicyValidInstTree *rootEntry = NULL;
872 Rm_PolicyValidInstNode *newNode = NULL;
873 char linuxName[] = RM_ALLOCATED_TO_LINUX;
874 int32_t instIndex;
876 /* Valid instance list must be first and only property in the root node of
877 * the policyDtb */
878 validInstOffset = fdt_first_property_offset(policyDtb,
879 RM_DTB_UTIL_STARTING_NODE_OFFSET);
880 if (validInstOffset < -FDT_ERR_NOTFOUND) {
881 *result = validInstOffset;
882 return(NULL);
883 }
885 if (validInstOffset == -FDT_ERR_NOTFOUND) {
886 *result = RM_ERROR_NO_VALID_INST_IN_POLICY;
887 return(NULL);
888 }
889 validInstData = fdt_getprop_by_offset(policyDtb, validInstOffset,
890 &validInstName, &validInstLen);
891 propertyType = rmDtbUtilPolicyGetPropertyType(validInstName);
892 if (propertyType != Rm_policyPropType_VALID_INSTANCES) {
893 *result = RM_ERROR_NO_VALID_INST_IN_POLICY;
894 return(NULL);
895 }
897 if (!(validInstList = rmDtbUtilPolicyExtractValidInstances(validInstData,
898 validInstLen,
899 result))) {
900 return(NULL);
901 }
903 /* Create the tree */
904 rootEntry = Rm_osalMalloc(sizeof(Rm_PolicyValidInstTree));
905 RB_INIT(rootEntry);
907 vInstListStart = validInstList;
908 /* Zeroeth index is reserved for global permissions */
909 instIndex = 1;
910 while (validInstList) {
911 newNode = rmPolicyValidInstNodeNew(validInstList->instName,
912 instIndex);
913 RB_INSERT(_Rm_PolicyValidInstTree, rootEntry, newNode);
915 instIndex++;
916 validInstList = validInstList->nextValidInst;
917 }
918 rmDtbUtilPolicyFreeValidInstances(vInstListStart);
920 /* Add the Linux kernel node */
921 if (addLinux) {
922 newNode = rmPolicyValidInstNodeNew(linuxName, instIndex++);
923 RB_INSERT(_Rm_PolicyValidInstTree, rootEntry, newNode);
924 }
926 /* Save the max index for proper accounting when validating against
927 * policy */
928 rmInst->maxInstIdx = instIndex;
930 *result = RM_OK;
931 return(rootEntry);
932 }
934 /* FUNCTION PURPOSE: Deletes a valid instance tree
935 ***********************************************************************
936 * DESCRIPTION: Frees all memory associated with a Policy valid
937 * instance tree.
938 */
939 void rmPolicyVInstTreeDelete(Rm_Handle rmHandle)
940 {
941 Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
942 Rm_PolicyValidInstTree *treeRoot = rmInst->validInstTree;
943 Rm_PolicyValidInstNode *node;
944 Rm_PolicyValidInstNode *nextNode;
946 if (treeRoot) {
947 if (rmInst->instType == Rm_instType_SHARED_SERVER) {
948 rmPolicyValidInstTreeInv(treeRoot);
949 }
951 for (node = RB_MIN(_Rm_PolicyValidInstTree, treeRoot);
952 node != NULL;
953 node = nextNode) {
954 nextNode = RB_NEXT(_Rm_PolicyValidInstTree, treeRoot, node);
955 RB_REMOVE(_Rm_PolicyValidInstTree, treeRoot, node);
956 rmPolicyValidInstNodeFree(node);
957 }
959 /* Don't need to writeback tree node changes since valid instance will
960 * be made NULL in instance */
962 if (RB_MIN(_Rm_PolicyValidInstTree, treeRoot) == NULL) {
963 /* No more valid instance nodes in tree */
964 Rm_osalFree((void *)treeRoot, sizeof(treeRoot));
965 }
967 rmInst->validInstTree = NULL;
968 }
969 }
971 /* FUNCTION PURPOSE: Populates an allocator's policy tree
972 ***********************************************************************
973 * DESCRIPTION: Populates an allocator's policy tree using the policy
974 * DTB
975 */
976 int32_t rmPolicyPopulateTree(Rm_Handle rmHandle, Rm_PolicyTree *policyTree,
977 void *policyDtb, const char *resName)
978 {
979 Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
980 int32_t resOffset;
981 uint32_t allocAlignment;
982 uint32_t cdAllocSize;
983 uint32_t permBufSizeBytes = 0;
984 int32_t propOffset;
985 const void *propData;
986 const char *propName;
987 int32_t propLen;
988 Rm_PolicyAssignment *assign = NULL;
989 Rm_PolicyAssignment *assignStart = NULL;
990 Rm_PolicyNode *polNode = NULL;
991 Rm_PolicyPermission *extractedPerms = NULL;
992 int32_t retVal = RM_OK;
994 /* Offset of resource in policy DTB */
995 resOffset = policyGetDtbResourceOffset(policyDtb, resName);
996 if (resOffset < 0) {
997 retVal = resOffset;
998 goto errorExit;
999 }
1001 /* Get the allocation alignment and the CD allocation size since these
1002 * will be stored in each tree node */
1003 allocAlignment = policyGetDtbAllocAlign(policyDtb, resOffset);
1004 cdAllocSize = policyGetDtbCdAllocSize(policyDtb, resOffset);
1005 permBufSizeBytes = policyGetPermBufSize(rmInst->maxInstIdx);
1007 /* Get the resource assignments - should only be one per resource node */
1008 propOffset = fdt_first_property_offset(policyDtb, resOffset);
1009 while (propOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
1010 propData = fdt_getprop_by_offset(policyDtb, propOffset, &propName,
1011 &propLen);
1012 if (rmDtbUtilPolicyGetPropertyType(propName) ==
1013 Rm_policyPropType_ASSIGNMENTS) {
1014 assign = assignStart = rmDtbUtilPolicyExtractAssignments(propData,
1015 propLen);
1016 break;
1017 }
1018 propOffset = fdt_next_property_offset(policyDtb, propOffset);
1019 }
1021 /* Insert a new node into resource's allocator for each assignment range */
1022 while (assign) {
1023 polNode = rmPolicyNodeNew(assign->resourceBase,
1024 assign->resourceLength);
1025 polNode->allocAlign = allocAlignment;
1026 polNode->cdAllocSize = cdAllocSize;
1027 polNode->perms = Rm_osalMalloc(permBufSizeBytes);
1028 polNode->permsLen = permBufSizeBytes;
1030 memset(polNode->perms, 0, polNode->permsLen);
1032 extractedPerms = policyGetAssignmentPermissions(assign, &retVal);
1033 if (retVal != RM_OK) {
1034 goto errorExit;
1035 }
1037 retVal = policyStorePermissions(rmInst, polNode, extractedPerms);
1038 if (retVal != RM_OK) {
1039 goto errorExit;
1040 }
1041 RB_INSERT(_Rm_AllocatorPolicyTree, policyTree, polNode);
1043 policyFreeAssignmentPermissions(extractedPerms);
1044 extractedPerms = NULL;
1045 polNode = NULL;
1047 assign = assign->nextAssignment;
1048 }
1050 errorExit:
1051 if (polNode) {
1052 rmPolicyNodeFree(polNode);
1053 }
1054 if (extractedPerms) {
1055 policyFreeAssignmentPermissions(extractedPerms);
1056 }
1057 if (assignStart) {
1058 rmDtbUtilPolicyFreeAssignments(assignStart);
1059 }
1061 return(retVal);
1062 }