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(Rm_PolicyPermBits *permsPtr,
458 uint32_t maxValidInst)
459 {
460 uint32_t instPerWord;
461 uint32_t numWords;
462 uint32_t totalBytes = 0;
464 instPerWord = RM_policy_PERM_INST_PER_WORD;
465 /* Round up */
466 numWords = (maxValidInst + instPerWord - 1) / instPerWord;
468 totalBytes = sizeof(*permsPtr) * numWords;
469 return(totalBytes);
470 }
472 /* FUNCTION PURPOSE: Stores policy permissions in a policy tree node
473 ***********************************************************************
474 * DESCRIPTION: Parses permissions and stores them in a word array in a
475 * compacted format. The array is attached to the resource's
476 * policy tree node.
477 */
478 static int32_t policyStorePermissions(Rm_Inst *rmInst, Rm_PolicyNode *polNode,
479 Rm_PolicyPermission *extractedPerms)
480 {
481 Rm_PolicyValidInstNode *vInst = NULL;
482 uint32_t instIdx;
483 uint32_t wordIndex;
484 uint32_t wordOffset;
485 int32_t retVal = RM_OK;
487 while (extractedPerms) {
488 if (!strncmp(extractedPerms->instName, Rm_policyGlobalInst,
489 RM_NAME_MAX_CHARS)) {
490 instIdx = RM_POLICY_GLOBAL_PERM_INDEX;
491 } else if ((vInst = rmPolicyGetValidInstNode((Rm_Handle)rmInst,
492 extractedPerms->instName))) {
493 instIdx = vInst->instIdx;
494 } else {
495 retVal = RM_ERROR_PERM_STR_INST_NOT_VALID;
496 goto errorExit;
497 }
499 /* Calculate word index into policy node's permission array
500 * for the instance index */
501 wordIndex = RM_policy_PERM_INDEX(instIdx);
502 wordOffset = RM_policy_PERM_OFFSET(instIdx);
504 polNode->perms[wordIndex] |= ((extractedPerms->permissionBits &
505 RM_policy_PERM_FULL_MASK) << wordOffset);
507 extractedPerms = extractedPerms->nextPermission;
508 }
510 errorExit:
511 return(retVal);
512 }
514 /* FUNCTION PURPOSE: Returns resource's allocation alignment from policy
515 ***********************************************************************
516 * DESCRIPTION: Parses the policy DTB to find and return a resource's
517 * allocation alignment.
518 */
519 static uint32_t policyGetDtbAllocAlign(void *policyDtb, int32_t resourceOffset)
520 {
521 int32_t offset;
522 const char *name;
523 int32_t len;
524 const void *data;
525 Rm_ResourceValue *alignList = NULL;
526 uint32_t align = 0;
528 offset = fdt_first_property_offset(policyDtb, resourceOffset);
529 while (offset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
530 data = fdt_getprop_by_offset(policyDtb, offset, &name, &len);
531 if (rmDtbUtilPolicyGetPropertyType(name) ==
532 Rm_policyPropType_ALLOCATION_ALIGNMENT) {
533 alignList = rmDtbUtilPolicyExtractResourceAlignments(data, len);
534 align = alignList->value;
535 break;
536 }
537 offset = fdt_next_property_offset(policyDtb, offset);
538 }
540 if (alignList) {
541 rmDtbUtilPolicyFreeResourceAlignments(alignList);
542 }
544 if (align == 0) {
545 align = 1;
546 }
547 return(align);
548 }
550 /* FUNCTION PURPOSE: Returns resource CD allocation size defined in policy
551 ***********************************************************************
552 * DESCRIPTION: Parses the policy DTB to find and return a resource's
553 * allocation size.
554 */
555 static uint32_t policyGetDtbCdAllocSize(void *policyDtb, int32_t resourceOffset)
556 {
557 int32_t offset;
558 const char *name;
559 int32_t len;
560 const void *data;
561 Rm_ResourceValue *allocSizeList = NULL;
562 uint32_t allocSize = 0;
564 offset = fdt_first_property_offset(policyDtb, resourceOffset);
565 while (offset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
566 data = fdt_getprop_by_offset(policyDtb, offset, &name, &len);
567 if (rmDtbUtilPolicyGetPropertyType(name) ==
568 Rm_policyPropType_CD_ALLOCATION_SIZE) {
569 allocSizeList = rmDtbUtilPolicyExtractCdAllocationSizes(data, len);
570 allocSize = allocSizeList->value;
571 break;
572 }
573 offset = fdt_next_property_offset(policyDtb, offset);
574 }
576 if (allocSizeList) {
577 rmDtbUtilPolicyFreeCdAllocationSizes(allocSizeList);
578 }
579 return(allocSize);
580 }
582 /* FUNCTION PURPOSE: Get a resource's offset into a policy
583 ***********************************************************************
584 * DESCRIPTION: Returns the location of the specified resource node
585 * within the specified Policy in the form of an offset
586 * into the DTB. The resourceName and the Policy
587 * node name must match.
588 */
589 static int32_t policyGetDtbResourceOffset(void *policyDtb,
590 const char *resourceName)
591 {
592 int32_t nodeOffset;
593 int32_t depth;
594 const char *nodeName;
596 if (policyDtb) {
597 depth = RM_DTB_UTIL_STARTING_DEPTH;
598 nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;
600 /* Find node offset for provided resource name */
601 while (nodeOffset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) {
602 nodeOffset = fdt_next_node(policyDtb, nodeOffset, &depth);
603 if (depth < RM_DTB_UTIL_STARTING_DEPTH) {
604 /* Resource name not found */
605 nodeOffset = RM_ERROR_RES_DOES_NOT_EXIST_IN_POLICY;
606 break;
607 } else {
608 nodeName = fdt_get_name(policyDtb, nodeOffset, NULL);
609 if (strncmp(nodeName, resourceName, RM_NAME_MAX_CHARS) == 0) {
610 break;
611 }
612 }
613 }
614 } else {
615 nodeOffset = RM_ERROR_INSTANCE_HAS_NO_POLICY;
616 }
617 return(nodeOffset);
618 }
620 /**********************************************************************
621 ************************ Internal Policy APIs ************************
622 **********************************************************************/
624 /* FUNCTION PURPOSE: Get a valid instace node from the valid inst tree
625 ***********************************************************************
626 * DESCRIPTION: Returns a valid instance node from the valid instance
627 * tree that matches the specified instName
628 */
629 Rm_PolicyValidInstNode *rmPolicyGetValidInstNode(Rm_Handle rmHandle,
630 const char *instName)
631 {
632 Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
633 Rm_PolicyValidInstTree *treeRoot = rmInst->validInstTree;
634 Rm_PolicyValidInstNode findNode;
636 rm_strncpy(findNode.name, instName, RM_NAME_MAX_CHARS);
637 return(RB_FIND(_Rm_PolicyValidInstTree, treeRoot, &findNode));
638 }
640 /* FUNCTION PURPOSE: Gets the Linux Valid instance node
641 ***********************************************************************
642 * DESCRIPTION: Returns a pointer to the valid instance node in the
643 * valid instance tree that matches the instance name
644 * reserved for resource assigned to the Linux kernel.
645 */
646 Rm_PolicyValidInstNode *rmPolicyGetLinuxInstNode(Rm_Handle rmHandle)
647 {
648 const char linuxName[] = RM_ALLOCATED_TO_LINUX;
650 return(rmPolicyGetValidInstNode(rmHandle, linuxName));
651 }
653 /* FUNCTION PURPOSE: Validates resource permissions against a Policy DTB
654 ***********************************************************************
655 * DESCRIPTION: Returns TRUE if the instance name has the specified
656 * permissions for the specified resource in the Policy
657 * DTB. Otherwise, returns FALSE.
658 */
659 int32_t rmPolicyCheckPrivilege(Rm_PolicyCheckCfg *privilegeCfg)
660 {
661 uint32_t permShift;
662 uint32_t globPermIdx;
663 uint32_t globPermOffset;
664 uint32_t instPermIdx;
665 uint32_t instPermOffset;
666 Rm_PolicyNode findNode;
667 Rm_PolicyNode *matchNode = NULL;
668 uint32_t findEnd;
669 uint32_t matchEnd;
670 int32_t isApproved = RM_FALSE;
672 switch (privilegeCfg->type) {
673 case Rm_policyCheck_INIT:
674 permShift = RM_POLICY_PERM_INIT_SHIFT;
675 break;
676 case Rm_policyCheck_USE:
677 permShift = RM_POLICY_PERM_USE_SHIFT;
678 break;
679 case Rm_policyCheck_EXCLUSIVE:
680 permShift = RM_POLICY_PERM_EXCLUSIVE_SHIFT;
681 break;
682 case Rm_policyCheck_SHARED_LINUX:
683 permShift = RM_POLICY_PERM_SHARED_LINUX_SHIFT;
684 break;
685 case Rm_policyCheck_UNSPEC_EXCLUSION:
686 permShift = RM_POLICY_PERM_UNSPEC_EXCLUSION_SHIFT;
687 break;
688 default:
689 return(isApproved);
690 }
692 /* Calculate the word indices and offsets for the global permissions and
693 * the specific instance */
694 globPermIdx = RM_policy_PERM_INDEX(RM_POLICY_GLOBAL_PERM_INDEX);
695 globPermOffset = RM_policy_PERM_OFFSET(RM_POLICY_GLOBAL_PERM_INDEX);
696 instPermIdx = RM_policy_PERM_INDEX(privilegeCfg->validInstNode->instIdx);
697 instPermOffset = RM_policy_PERM_OFFSET(privilegeCfg->validInstNode->instIdx);
699 memset((void *)&findNode, 0, sizeof(findNode));
700 findNode.base = privilegeCfg->resourceBase;
701 findNode.len = privilegeCfg->resourceLength;
702 /* Get first matching node. */
703 matchNode = RB_FIND(_Rm_AllocatorPolicyTree, privilegeCfg->polTree,
704 &findNode);
705 if (matchNode) {
706 /* Request range may not be completely contained within the first
707 * matching node. Find furthest left matching node for the request
708 * range */
709 while (findNode.base < matchNode->base) {
710 matchNode = RB_PREV(_Rm_AllocatorPolicyTree,
711 privilegeCfg->polTree, matchNode);
712 }
713 }
715 /* Check permissions across all policy nodes which the request range
716 * spans. Assume approved until denial found */
717 isApproved = RM_TRUE;
718 while (matchNode) {
719 if (privilegeCfg->negCheck) {
720 /* Not approved if any matching node is assigned an exclusion
721 * permission */
722 if ((RM_policy_PERM_GET(matchNode->perms, globPermIdx,
723 globPermOffset, permShift)) ||
724 (RM_policy_PERM_GET(matchNode->perms, instPermIdx,
725 instPermOffset, permShift))) {
726 isApproved = RM_FALSE;
727 break;
728 }
729 } else {
730 /* Not approved if any matching node does not have permission */
731 if ((!RM_policy_PERM_GET(matchNode->perms, globPermIdx,
732 globPermOffset, permShift)) &&
733 (!RM_policy_PERM_GET(matchNode->perms, instPermIdx,
734 instPermOffset, permShift))) {
735 isApproved = RM_FALSE;
736 break;
737 }
738 }
740 matchEnd = matchNode->base + matchNode->len - 1;
741 findEnd = findNode.base + findNode.len - 1;
743 /* Check node to right if request range spans matching node to right */
744 if (findEnd > matchEnd) {
745 matchNode = RB_NEXT(_Rm_AllocatorPolicyTree, privilegeCfg->polTree,
746 matchNode);
747 if (matchNode == NULL) {
748 /* Request range outspans actual resource range */
749 isApproved = RM_FALSE;
750 }
751 } else {
752 break;
753 }
754 }
756 return(isApproved);
757 }
759 /* FUNCTION PURPOSE: Returns resource base value according to the Policy
760 ***********************************************************************
761 * DESCRIPTION: Returns a resource base value based on the resource
762 * ranges assigned to the specified valid instance by the
763 * Policy DTB.
764 */
765 int32_t rmPolicyGetResourceBase(Rm_PolicyTree *policyTree,
766 Rm_PolicyValidInstNode *validInstNode,
767 Rm_PolicyCheckType checkType,
768 int32_t *resBase)
769 {
770 uint32_t permShift = RM_POLICY_PERM_INIT_SHIFT;
771 uint32_t globPermIdx;
772 uint32_t globPermOffset;
773 uint32_t instPermIdx;
774 uint32_t instPermOffset;
775 Rm_PolicyNode *polNode;
777 *resBase = RM_RESOURCE_BASE_UNSPECIFIED;
779 if (checkType == Rm_policyCheck_INIT) {
780 permShift = RM_POLICY_PERM_INIT_SHIFT;
781 } else if (checkType == Rm_policyCheck_USE) {
782 permShift = RM_POLICY_PERM_USE_SHIFT;
783 } else {
784 return(RM_ERROR_INVALID_SERVICE_TYPE);
785 }
787 /* Calculate the word indices and offsets for the global permissions and
788 * the specific instance */
789 globPermIdx = RM_policy_PERM_INDEX(RM_POLICY_GLOBAL_PERM_INDEX);
790 globPermOffset = RM_policy_PERM_OFFSET(RM_POLICY_GLOBAL_PERM_INDEX);
791 instPermIdx = RM_policy_PERM_INDEX(validInstNode->instIdx);
792 instPermOffset = RM_policy_PERM_OFFSET(validInstNode->instIdx);
794 RB_FOREACH(polNode, _Rm_AllocatorPolicyTree, policyTree) {
795 if (RM_policy_PERM_GET(polNode->perms, globPermIdx, globPermOffset,
796 permShift) ||
797 RM_policy_PERM_GET(polNode->perms, instPermIdx, instPermOffset,
798 permShift)) {
799 *resBase = polNode->base;
800 break;
801 }
802 }
804 if (*resBase == RM_RESOURCE_BASE_UNSPECIFIED) {
805 return(RM_SERVICE_DENIED_RES_ALLOC_REQS_NOT_MET);
806 }
808 return(RM_OK);
809 }
811 /* FUNCTION PURPOSE: Returns resource's allocation alignment
812 ***********************************************************************
813 * DESCRIPTION: Returns a resource's allocation alignment.
814 */
815 uint32_t rmPolicyGetAllocAlign(Rm_PolicyTree *policyTree)
816 {
817 Rm_PolicyNode *node = NULL;
818 uint32_t align = 1;
820 /* Resource's alignment is global at the moment so all policy tree nodes
821 * store the same value. Just get the min node and return the allocation
822 * alignment from it */
823 node = RB_MIN(_Rm_AllocatorPolicyTree, policyTree);
824 if (node) {
825 align = node->allocAlign;
826 }
828 return(align);
829 }
831 /* FUNCTION PURPOSE: Returns resource's CD allocation size
832 ***********************************************************************
833 * DESCRIPTION: Returns a resource's CD allocation size.
834 */
835 uint32_t rmPolicyGetCdAllocSize(Rm_PolicyTree *policyTree)
836 {
837 Rm_PolicyNode *node = NULL;
838 uint32_t allocSize = 0;
840 /* Resource's CD allocation size is global at the moment so all policy
841 * tree nodes store the same value. Just get the min node and return
842 * allocation size from it */
843 node = RB_MIN(_Rm_AllocatorPolicyTree, policyTree);
844 if (node) {
845 allocSize = node->cdAllocSize;
846 }
848 return(allocSize);
849 }
851 /* FUNCTION PURPOSE: Initializes the valid instance tree for a RM instance
852 ***********************************************************************
853 * DESCRIPTION: Creates the valid instance tree for a RM instance
854 * that has been provided a global or static policy
855 * The valid instance tree is created from the
856 * "valid-instances" property at the top of the Policy.
857 * The root entry of the valid instance tree is returned.
858 */
859 Rm_PolicyValidInstTree *rmPolicyVInstTreeInit(Rm_Handle rmHandle,
860 void *policyDtb,
861 int addLinux,
862 int32_t *result)
863 {
864 Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
865 int32_t validInstOffset;
866 const char *validInstName = NULL;
867 int32_t validInstLen;
868 const void *validInstData = NULL;
869 Rm_PolicyPropType propertyType;
870 Rm_PolicyValidInst *vInstListStart = NULL;
871 Rm_PolicyValidInst *validInstList = NULL;
872 Rm_PolicyValidInstTree *rootEntry = NULL;
873 Rm_PolicyValidInstNode *newNode = NULL;
874 char linuxName[] = RM_ALLOCATED_TO_LINUX;
875 int32_t instIndex;
877 /* Valid instance list must be first and only property in the root node of
878 * the policyDtb */
879 validInstOffset = fdt_first_property_offset(policyDtb,
880 RM_DTB_UTIL_STARTING_NODE_OFFSET);
881 if (validInstOffset < -FDT_ERR_NOTFOUND) {
882 *result = validInstOffset;
883 return(NULL);
884 }
886 if (validInstOffset == -FDT_ERR_NOTFOUND) {
887 *result = RM_ERROR_NO_VALID_INST_IN_POLICY;
888 return(NULL);
889 }
890 validInstData = fdt_getprop_by_offset(policyDtb, validInstOffset,
891 &validInstName, &validInstLen);
892 propertyType = rmDtbUtilPolicyGetPropertyType(validInstName);
893 if (propertyType != Rm_policyPropType_VALID_INSTANCES) {
894 *result = RM_ERROR_NO_VALID_INST_IN_POLICY;
895 return(NULL);
896 }
898 if (!(validInstList = rmDtbUtilPolicyExtractValidInstances(validInstData,
899 validInstLen,
900 result))) {
901 return(NULL);
902 }
904 /* Create the tree */
905 rootEntry = Rm_osalMalloc(sizeof(Rm_PolicyValidInstTree));
906 RB_INIT(rootEntry);
908 vInstListStart = validInstList;
909 /* Zeroeth index is reserved for global permissions */
910 instIndex = 1;
911 while (validInstList) {
912 newNode = rmPolicyValidInstNodeNew(validInstList->instName,
913 instIndex);
914 RB_INSERT(_Rm_PolicyValidInstTree, rootEntry, newNode);
916 instIndex++;
917 validInstList = validInstList->nextValidInst;
918 }
919 rmDtbUtilPolicyFreeValidInstances(vInstListStart);
921 /* Add the Linux kernel node */
922 if (addLinux) {
923 newNode = rmPolicyValidInstNodeNew(linuxName, instIndex++);
924 RB_INSERT(_Rm_PolicyValidInstTree, rootEntry, newNode);
925 }
927 /* Save the max index for proper accounting when validating against
928 * policy */
929 rmInst->maxInstIdx = instIndex;
931 *result = RM_OK;
932 return(rootEntry);
933 }
935 /* FUNCTION PURPOSE: Deletes a valid instance tree
936 ***********************************************************************
937 * DESCRIPTION: Frees all memory associated with a Policy valid
938 * instance tree.
939 */
940 void rmPolicyVInstTreeDelete(Rm_Handle rmHandle)
941 {
942 Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
943 Rm_PolicyValidInstTree *treeRoot = rmInst->validInstTree;
944 Rm_PolicyValidInstNode *node;
945 Rm_PolicyValidInstNode *nextNode;
947 if (treeRoot) {
948 if (rmInst->instType == Rm_instType_SHARED_SERVER) {
949 rmPolicyValidInstTreeInv(treeRoot);
950 }
952 for (node = RB_MIN(_Rm_PolicyValidInstTree, treeRoot);
953 node != NULL;
954 node = nextNode) {
955 nextNode = RB_NEXT(_Rm_PolicyValidInstTree, treeRoot, node);
956 RB_REMOVE(_Rm_PolicyValidInstTree, treeRoot, node);
957 rmPolicyValidInstNodeFree(node);
958 }
960 /* Don't need to writeback tree node changes since valid instance will
961 * be made NULL in instance */
963 if (RB_MIN(_Rm_PolicyValidInstTree, treeRoot) == NULL) {
964 /* No more valid instance nodes in tree */
965 Rm_osalFree((void *)treeRoot, sizeof(treeRoot));
966 }
968 rmInst->validInstTree = NULL;
969 }
970 }
972 /* FUNCTION PURPOSE: Populates an allocator's policy tree
973 ***********************************************************************
974 * DESCRIPTION: Populates an allocator's policy tree using the policy
975 * DTB
976 */
977 int32_t rmPolicyPopulateTree(Rm_Handle rmHandle, Rm_PolicyTree *policyTree,
978 void *policyDtb, const char *resName)
979 {
980 Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
981 int32_t resOffset;
982 uint32_t allocAlignment;
983 uint32_t cdAllocSize;
984 uint32_t permBufSizeBytes = 0;
985 int32_t propOffset;
986 const void *propData;
987 const char *propName;
988 int32_t propLen;
989 Rm_PolicyAssignment *assign = NULL;
990 Rm_PolicyAssignment *assignStart = NULL;
991 Rm_PolicyNode *polNode = NULL;
992 Rm_PolicyPermission *extractedPerms = NULL;
993 int32_t retVal = RM_OK;
995 /* Offset of resource in policy DTB */
996 resOffset = policyGetDtbResourceOffset(policyDtb, resName);
997 if (resOffset < 0) {
998 retVal = resOffset;
999 goto errorExit;
1000 }
1002 /* Get the allocation alignment and the CD allocation size since these
1003 * will be stored in each tree node */
1004 allocAlignment = policyGetDtbAllocAlign(policyDtb, resOffset);
1005 cdAllocSize = policyGetDtbCdAllocSize(policyDtb, resOffset);
1006 permBufSizeBytes = policyGetPermBufSize(polNode->perms, rmInst->maxInstIdx);
1008 /* Get the resource assignments - should only be one per resource node */
1009 propOffset = fdt_first_property_offset(policyDtb, resOffset);
1010 while (propOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
1011 propData = fdt_getprop_by_offset(policyDtb, propOffset, &propName,
1012 &propLen);
1013 if (rmDtbUtilPolicyGetPropertyType(propName) ==
1014 Rm_policyPropType_ASSIGNMENTS) {
1015 assign = assignStart = rmDtbUtilPolicyExtractAssignments(propData,
1016 propLen);
1017 break;
1018 }
1019 propOffset = fdt_next_property_offset(policyDtb, propOffset);
1020 }
1022 /* Insert a new node into resource's allocator for each assignment range */
1023 while (assign) {
1024 polNode = rmPolicyNodeNew(assign->resourceBase,
1025 assign->resourceLength);
1026 polNode->allocAlign = allocAlignment;
1027 polNode->cdAllocSize = cdAllocSize;
1028 polNode->perms = Rm_osalMalloc(permBufSizeBytes);
1029 polNode->permsLen = permBufSizeBytes;
1031 memset(polNode->perms, 0, polNode->permsLen);
1033 extractedPerms = policyGetAssignmentPermissions(assign, &retVal);
1034 if (retVal != RM_OK) {
1035 goto errorExit;
1036 }
1038 retVal = policyStorePermissions(rmInst, polNode, extractedPerms);
1039 if (retVal != RM_OK) {
1040 goto errorExit;
1041 }
1042 RB_INSERT(_Rm_AllocatorPolicyTree, policyTree, polNode);
1044 policyFreeAssignmentPermissions(extractedPerms);
1045 extractedPerms = NULL;
1046 polNode = NULL;
1048 assign = assign->nextAssignment;
1049 }
1051 errorExit:
1052 if (polNode) {
1053 rmPolicyNodeFree(polNode);
1054 }
1055 if (extractedPerms) {
1056 policyFreeAssignmentPermissions(extractedPerms);
1057 }
1058 if (assignStart) {
1059 rmDtbUtilPolicyFreeAssignments(assignStart);
1060 }
1062 return(retVal);
1063 }