diff --git a/src/rm_policy.c b/src/rm_policy.c
index f2b11a58d10cfee01059a50a2095b535baf52e74..68d63931b1e4e7553f54c6d87695a48deaaffa89 100644 (file)
--- a/src/rm_policy.c
+++ b/src/rm_policy.c
/**
- * @file rmpolicy.c
+ * @file rm_policy.c
*
* @brief
- * This is the Resource Manager Policy source.
+ * Resource Manager Policy source.
*
* \par
* ============================================================================
- * @n (C) Copyright 2012, Texas Instruments, Inc.
+ * @n (C) Copyright 2012-2013, Texas Instruments, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* \par
*/
-/* RM Types */
-#include <ti/drv/rm/rm_types.h>
+/* Standard includes */
+#include <ctype.h>
/* RM external API includes */
-#include <ti/drv/rm/rm_policy.h>
+#include <ti/drv/rm/rm.h>
/* RM internal API includes */
-//#include <ti/drv/rm/include/rm_policyloc.h>
+#include <ti/drv/rm/include/rm_internal.h>
+#include <ti/drv/rm/include/rm_loc.h>
+#include <ti/drv/rm/include/rm_allocatorloc.h>
+#include <ti/drv/rm/include/rm_policyloc.h>
+#include <ti/drv/rm/include/rm_dtb_utilloc.h>
+
+/* RM LIBFDT includes */
+#include <ti/drv/rm/util/libfdt/libfdt.h>
+
+/* Tree algorithm includes */
+#include <ti/drv/rm/util/tree.h>
/* RM OSAL layer */
#include <rm_osal.h>
+/**********************************************************************
+ *********************** Policy Globals *******************************
+ **********************************************************************/
+
+/* Character used in Policies to specify all RM instances receive
+ * the defined permissions for a resource node */
+const char Rm_policyAllInstances[] = "*";
+
+/**********************************************************************
+ ******************** Local Policy Functions **************************
+ **********************************************************************/
+
+/* FUNCTION PURPOSE: Returns a pointer to the valid instance tree
+ ***********************************************************************
+ * DESCRIPTION: Returns a pointer to the instance's valid instance
+ * tree based on the instance type
+ */
+static Rm_PolicyValidInstTree *policyGetValidInstTree(Rm_Handle rmHandle)
+{
+ Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
+ Rm_PolicyValidInstTree *tree = NULL;
+
+ if ((rmInst->instType == Rm_instType_SERVER) ||
+ (rmInst->instType == Rm_instType_SHARED_SERVER)) {
+ tree = rmInst->u.server.globalValidInstTree;
+ }
+ else if (rmInst->instType == Rm_instType_CLIENT_DELEGATE) {
+ tree = rmInst->u.cd.cdValidInstTree;
+ }
+ else if (rmInst->instType == Rm_instType_CLIENT) {
+ tree = rmInst->u.client.staticValidInstTree;
+ }
+ return(tree);
+}
+
+/* FUNCTION PURPOSE: Validates the instance names in a permissions string
+ ***********************************************************************
+ * DESCRIPTION: Returns RM_OK if all the instance names in a permissions
+ * string match instance names defined in the valid instance
+ * list. RM_ERROR_PERM_STR_INST_NOT_VALID is returned if
+ * there are any mismatches
+ */
+static int32_t policyCheckInstances(Rm_Handle rmHandle, Rm_PolicyPermission *permissionsList)
+{
+ while (permissionsList) {
+ if (strncmp(permissionsList->instName, Rm_policyAllInstances, RM_NAME_MAX_CHARS) &&
+ (!rmPolicyGetValidInstNode(rmHandle, permissionsList->instName))) {
+ return(RM_ERROR_PERM_STR_INST_NOT_VALID);
+ }
+ permissionsList = permissionsList->nextPermission;
+ }
+ return(RM_OK);
+}
+
+/* FUNCTION PURPOSE: Parses a permissions subgroup
+ ***********************************************************************
+ * DESCRIPTION: Returns a linked list of policy permissions defining
+ * which RM instance referenced in the permissions subgroup
+ * get which permissions. Returns NULL if any syntax
+ * errors are encountered during the parsing. The error
+ * is returned via the result pointer parameter.
+ */
+static Rm_PolicyPermission *policyParseSubPermission(char *permStrStart, char *permStrEnd,
+ int32_t *result)
+{
+ Rm_PolicyPermission *startPerm = NULL;
+ Rm_PolicyPermission *newPerm = NULL;
+ Rm_PolicyPermission *prevPerm = NULL;
+ Rm_PolicyPermission *nextPerm = NULL;
+ char *permStrPtr = NULL;
+ char *subgroupStart = NULL;
+ char *subgroupEnd = NULL;
+ uint32_t permStrLen = (uint32_t)(permStrEnd - permStrStart + 1);
+ char instNameTemp[RM_NAME_MAX_CHARS];
+ uint32_t instNameIndex;
+ int foundInstName;
+ int instNameComplete;
+ int assignmentLeft;
+ int assignmentRight;
+
+ /* Create a local copy of the sub-permission string */
+ permStrPtr = Rm_osalMalloc(permStrLen);
+ strncpy(permStrPtr, permStrStart, permStrLen);
+ /* Make sure the last character in the copied sub-permission string is null */
+ permStrPtr[permStrLen - 1] = '\0';
+
+ permStrStart = permStrPtr;
+ permStrEnd = permStrPtr + strlen(permStrPtr);
+
+ /* Find the beginning and end of the sub-permission instance group */
+ subgroupStart = strchr(permStrStart, RM_POLICY_PERM_SUBGROUP_START);
+ subgroupEnd = strchr(permStrStart, RM_POLICY_PERM_SUBGROUP_END);
+
+ if ((!subgroupStart) || (!subgroupEnd) || (subgroupStart > subgroupEnd) ||
+ ((subgroupStart != strrchr(permStrStart, RM_POLICY_PERM_SUBGROUP_START)) &&
+ (subgroupEnd != strrchr(permStrStart, RM_POLICY_PERM_SUBGROUP_END)))) {
+ /* Free the memory associated with the temp string and return an error if:
+ * a) Could not find the instance group start
+ * b) Could not find the instance group end
+ * c) Subgroup start and end are out of order
+ * d) There is more than one instance subgroup specified in the string. There
+ * should only be one subgroup per sub-permission string */
+ *result = RM_ERROR_PERM_STR_TOO_MANY_INST_GROUPS;
+ goto parseError;
+ }
+
+ /* Create a permission entry for each instance specified in the instance group.
+ * Instances names are separated by one or more spaces. */
+ permStrPtr = subgroupStart + 1;
+ instNameIndex = 0;
+ foundInstName = RM_FALSE;
+ instNameComplete = RM_FALSE;
+ while (permStrPtr <= subgroupEnd) {
+ if ((isspace(*permStrPtr) || (*permStrPtr == RM_POLICY_PERM_SUBGROUP_END))
+ && foundInstName) {
+ /* First space encountered after copying an instance name. This
+ * terminates the instance name. All other space characters are
+ * ignored. */
+ instNameTemp[instNameIndex] = '\0';
+ instNameComplete = RM_TRUE;
+ }
+ else {
+ if (!foundInstName) {
+ /* First non-whitespace character encountered is the start of an
+ * instance name */
+ foundInstName = RM_TRUE;
+ }
+
+ /* Copy the character into the temporary instance name string */
+ instNameTemp[instNameIndex++] = *permStrPtr;
+ }
+
+ if (instNameComplete) {
+ newPerm = (Rm_PolicyPermission *) Rm_osalMalloc(sizeof(Rm_PolicyPermission));
+ memset((void *)newPerm, 0, sizeof(Rm_PolicyPermission));
+
+ strncpy(newPerm->instName, instNameTemp, RM_NAME_MAX_CHARS);
+ newPerm->nextPermission = NULL;
+
+ if (prevPerm == NULL) {
+ /* Save the first instance so it can be returned */
+ startPerm = newPerm;
+ }
+ else {
+ prevPerm->nextPermission = newPerm;
+ }
+ prevPerm = newPerm;
+
+ instNameComplete = RM_FALSE;
+ instNameIndex = 0;
+ foundInstName = RM_FALSE;
+ }
+ else if (instNameIndex == RM_NAME_MAX_CHARS) {
+ /* Instance name is longer than max length */
+ *result = RM_ERROR_INST_NAME_IN_ASSIGNMENT_TOO_LONG;
+ goto parseError;
+ }
+
+ permStrPtr++;
+ }
+
+ /* Fill in the permissions for each instance name */
+
+ /* Look on left of instance group for permission assignments. */
+ permStrPtr = subgroupStart - 1;
+ assignmentLeft = RM_FALSE;
+ while (permStrPtr >= permStrStart)
+ {
+ if (*permStrPtr == RM_POLICY_PERM_ASSIGNMENT) {
+ if (assignmentLeft) {
+ /* Assignment character has been found more than once. This is a
+ * syntax error. Free the permission list and the temporary string
+ * and return. */
+ *result = RM_ERROR_PERM_STR_TOO_MANY_ASSIGN_CHARS;
+ goto parseError;
+ }
+ else {
+ assignmentLeft = RM_TRUE;
+ }
+ }
+ else if (!isspace(*permStrPtr)) {
+ if (assignmentLeft) {
+ if ((*permStrPtr == RM_POLICY_PERM_INIT_LOWER) ||
+ (*permStrPtr == RM_POLICY_PERM_INIT_UPPER)) {
+ newPerm = startPerm;
+ while (newPerm) {
+ RM_policy_SET_PERM(newPerm->permissionBits, RM_POLICY_PERM_INIT_SHIFT, 1);
+ newPerm = newPerm->nextPermission;
+ }
+ }
+ else if ((*permStrPtr == RM_POLICY_PERM_USE_LOWER) ||
+ (*permStrPtr == RM_POLICY_PERM_USE_UPPER)) {
+ newPerm = startPerm;
+ while (newPerm) {
+ RM_policy_SET_PERM(newPerm->permissionBits, RM_POLICY_PERM_USE_SHIFT, 1);
+ newPerm = newPerm->nextPermission;
+ }
+ }
+ else if ((*permStrPtr == RM_POLICY_PERM_EXCLUSIVE_LOWER) ||
+ (*permStrPtr == RM_POLICY_PERM_EXCLUSIVE_UPPER)) {
+ newPerm = startPerm;
+ while (newPerm) {
+ RM_policy_SET_PERM(newPerm->permissionBits, RM_POLICY_PERM_EXCLUSIVE_SHIFT, 1);
+ newPerm = newPerm->nextPermission;
+ }
+ }
+ else if ((*permStrPtr == RM_POLICY_PERM_SHARED_LINUX_LOWER) ||
+ (*permStrPtr == RM_POLICY_PERM_SHARED_LINUX_UPPER)) {
+ newPerm = startPerm;
+ while (newPerm) {
+ RM_policy_SET_PERM(newPerm->permissionBits, RM_POLICY_PERM_SHARED_LINUX_SHIFT, 1);
+ newPerm = newPerm->nextPermission;
+ }
+ }
+ else {
+ /* Invalid permission character. This is a
+ * syntax error. Free the permission list and the temporary string
+ * and return. */
+ *result = RM_ERROR_PERM_STR_INVALID_CHAR;
+ goto parseError;
+ }
+ }
+ else {
+ /* Character found without the assignment character being found. This is a
+ * syntax error. Free the permission list and the temporary string
+ * and return. */
+ *result = RM_ERROR_PERM_CHAR_WITHOUT_ASSIGN_CHAR;
+ goto parseError;
+ }
+ }
+ permStrPtr--;
+ }
+
+ /* Look on right of instance group for permission assignments. */
+ permStrPtr = subgroupEnd + 1;
+ assignmentRight = RM_FALSE;
+ while (permStrPtr < permStrEnd) {
+ if (assignmentLeft && (!isspace(*permStrPtr))) {
+ /* There should be nothing but spaces on right if assignment was already found on left */
+ *result = RM_ERROR_INVALID_PERMS_CHAR_ON_RIGHT;
+ goto parseError;
+ }
+
+ if (*permStrPtr == RM_POLICY_PERM_ASSIGNMENT) {
+ if (assignmentRight) {
+ /* Assignment character has been found more than once. This is a
+ * syntax error. Free the permission list and the temporary string
+ * and return. */
+ *result = RM_ERROR_PERM_STR_TOO_MANY_ASSIGN_CHARS;
+ goto parseError;
+ }
+ else {
+ assignmentRight = RM_TRUE;
+ }
+ }
+ else if (!isspace(*permStrPtr)) {
+ if (assignmentRight) {
+ if ((*permStrPtr == RM_POLICY_PERM_INIT_LOWER) ||
+ (*permStrPtr == RM_POLICY_PERM_INIT_UPPER)) {
+ newPerm = startPerm;
+ while (newPerm) {
+ RM_policy_SET_PERM(newPerm->permissionBits, RM_POLICY_PERM_INIT_SHIFT, 1);
+ newPerm = newPerm->nextPermission;
+ }
+ }
+ else if ((*permStrPtr == RM_POLICY_PERM_USE_LOWER) ||
+ (*permStrPtr == RM_POLICY_PERM_USE_UPPER)) {
+ newPerm = startPerm;
+ while (newPerm) {
+ RM_policy_SET_PERM(newPerm->permissionBits, RM_POLICY_PERM_USE_SHIFT, 1);
+ newPerm = newPerm->nextPermission;
+ }
+ }
+ else if ((*permStrPtr == RM_POLICY_PERM_EXCLUSIVE_LOWER) ||
+ (*permStrPtr == RM_POLICY_PERM_EXCLUSIVE_UPPER)) {
+ newPerm = startPerm;
+ while (newPerm) {
+ RM_policy_SET_PERM(newPerm->permissionBits, RM_POLICY_PERM_EXCLUSIVE_SHIFT, 1);
+ newPerm = newPerm->nextPermission;
+ }
+ }
+ else if ((*permStrPtr == RM_POLICY_PERM_SHARED_LINUX_LOWER) ||
+ (*permStrPtr == RM_POLICY_PERM_SHARED_LINUX_UPPER)) {
+ newPerm = startPerm;
+ while (newPerm) {
+ RM_policy_SET_PERM(newPerm->permissionBits, RM_POLICY_PERM_SHARED_LINUX_SHIFT, 1);
+ newPerm = newPerm->nextPermission;
+ }
+ }
+ else {
+ /* Invalid permission character. This is a
+ * syntax error. Free the permission list and the temporary string
+ * and return. */
+ *result = RM_ERROR_PERM_STR_INVALID_CHAR;
+ goto parseError;
+ }
+ }
+ else {
+ /* Character found without the assignment character being found. This is a
+ * syntax error. Free the permission list and the temporary string
+ * and return. */
+ *result = RM_ERROR_PERM_STR_TOO_MANY_ASSIGN_CHARS;
+ goto parseError;
+ }
+ }
+ permStrPtr++;
+ }
+
+ Rm_osalFree((void *)permStrStart, sizeof(permStrLen));
+ *result = RM_OK;
+ return (startPerm);
+
+parseError:
+ while (startPerm) {
+ nextPerm = startPerm->nextPermission;
+ Rm_osalFree((void *)startPerm, sizeof(Rm_PolicyPermission));
+ startPerm = nextPerm;
+ }
+ Rm_osalFree((void *)permStrStart, sizeof(permStrLen));
+ return(NULL);
+}
+
+/* FUNCTION PURPOSE: Frees a linked list of assignment permissions
+ ***********************************************************************
+ * DESCRIPTION: Frees the memory associated with a linked list of
+ * assignment permissions extracted from a permissions
+ * assignment subgroup in a policy DTB.
+ */
+static void policyFreeAssignmentPermissions(Rm_PolicyPermission *permissionList)
+{
+ Rm_PolicyPermission *nextPerm;
+
+ while (permissionList) {
+ nextPerm = permissionList->nextPermission;
+ Rm_osalFree((void *)permissionList, sizeof(Rm_PolicyPermission));
+ permissionList = nextPerm;
+ }
+}
+
+/* FUNCTION PURPOSE: Extracts permissions from a Policy "assignment"
+ ***********************************************************************
+ * DESCRIPTION: Returns a linked list of permissions for a resource node
+ * containing an "assignment" property in the Policy DTB.
+ * Each node in the linked list will contain a valid instance
+ * name along with the permissions assigned to the instance
+ */
+static Rm_PolicyPermission *policyGetAssignmentPermissions(Rm_PolicyAssignment *assignment,
+ int32_t *result)
+{
+ Rm_PolicyPermission *startPerm = NULL;
+ Rm_PolicyPermission *newPerm = NULL;
+ Rm_PolicyPermission *prevPerm = NULL;
+ char *permStrStart = assignment->permissionsList;
+ char *permStrEnd;
+ uint32_t permStrLen = strlen(assignment->permissionsList) + 1;
+ uint32_t i = 0;
+
+ *result = RM_OK;
+
+ while(i < permStrLen) {
+ /* Find the first sub-permission specification and parse it. A sub-permission
+ * can be terminated by the termination character or the end of the string. */
+ if (!(permStrEnd = strchr(permStrStart, RM_POLICY_PERM_TERMINATOR))) {
+ /* Sub-permission termination character not found. The permission string
+ * end is the end of the entire permission string */
+ permStrEnd = permStrStart + strlen(permStrStart);
+ }
+
+ newPerm = policyParseSubPermission(permStrStart, permStrEnd, result);
+
+ if (*result != RM_OK) {
+ /* Delete the permission list that's been created thus far, return
+ * the error and NULL for the permission list */
+ policyFreeAssignmentPermissions(startPerm);
+ return(NULL);
+ }
+
+ if (prevPerm == NULL) {
+ startPerm = newPerm;
+ }
+ else {
+ prevPerm->nextPermission = newPerm;
+ }
+
+ /* Set prevPerm to the last sub-permission returned by the sub-permission parser */
+ prevPerm = newPerm;
+ while(prevPerm->nextPermission != NULL) {
+ prevPerm = prevPerm->nextPermission;
+ }
+
+ /* Update the number of characters parsed from the permission list and point to
+ * the start of the next sub-permission */
+ i += ((uint32_t)(permStrEnd - permStrStart + 1));
+ permStrStart = permStrEnd + 1;
+ }
+
+ return(startPerm);
+}
+
+/* FUNCTION PURPOSE: Validates a policy "assignment" string list
+ ***********************************************************************
+ * DESCRIPTION: Returns RM_OK if the specified Policy DTB "assignment"
+ * property specification parses okay and all the RM
+ * instances in the assignment match RM instances in the
+ * valid instances list
+ */
+static int32_t policyValidateAssignmentPermissions(Rm_Handle rmHandle,
+ Rm_PolicyAssignment *assignmentList)
+{
+ Rm_PolicyAssignment *assignment = assignmentList;
+ Rm_PolicyPermission *permissionList;
+ int32_t result;
+
+ while (assignment) {
+ /* Make sure assignment's permissions parse okay */
+ permissionList = policyGetAssignmentPermissions(assignment, &result);
+ if (result != RM_OK) {
+ return(result);
+ }
+
+ if (result = policyCheckInstances(rmHandle, permissionList) != RM_OK) {
+ policyFreeAssignmentPermissions(permissionList);
+ return(result);
+ }
+
+ policyFreeAssignmentPermissions(permissionList);
+ assignment = assignment->nextAssignment;
+ }
+
+ return (RM_OK);
+}
+
+/**********************************************************************
+ ************************ Internal Policy APIs ************************
+ **********************************************************************/
+
+/* FUNCTION PURPOSE: Returns a pointer to the instance policy
+ ***********************************************************************
+ * DESCRIPTION: Returns a pointer to the instance's policy based on
+ * the instance type
+ */
+void *rmPolicyGetPolicy(Rm_Handle rmHandle)
+{
+ Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
+ void *policy = NULL;
+
+ if ((rmInst->instType == Rm_instType_SERVER) ||
+ (rmInst->instType == Rm_instType_SHARED_SERVER)) {
+ policy = rmInst->u.server.globalPolicy;
+ }
+ else if (rmInst->instType == Rm_instType_CLIENT_DELEGATE) {
+ policy = rmInst->u.cd.cdPolicy;
+ }
+ else if (rmInst->instType == Rm_instType_CLIENT) {
+ policy = rmInst->u.client.staticPolicy;
+ }
+ return(policy);
+}
+
+/* FUNCTION PURPOSE: Get a valid instace node from the valid inst tree
+ ***********************************************************************
+ * DESCRIPTION: Returns a valid instance node from the valid instance
+ * tree that matches the specified instName
+ */
+Rm_PolicyValidInstNode *rmPolicyGetValidInstNode(Rm_Handle rmHandle, char *instName)
+{
+ Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
+ Rm_PolicyValidInstTree *treeRoot = policyGetValidInstTree(rmHandle);
+ Rm_PolicyValidInstNode findNode;
+
+ if (rmInst->instType == Rm_instType_SHARED_SERVER) {
+ rmPolicyValidInstTreeInv(treeRoot);
+ }
+
+ memset((void *)&findNode, 0, sizeof(Rm_PolicyValidInstNode));
+ strncpy(findNode.name, instName, RM_NAME_MAX_CHARS);
+
+ return (RB_FIND(_Rm_PolicyValidInstTree, treeRoot, &findNode));
+}
+
+/* FUNCTION PURPOSE: Gets the Linux Valid instance node
+ ***********************************************************************
+ * DESCRIPTION: Returns a pointer to the valid instance node in the
+ * valid instance tree that matches the instance name
+ * reserved for resource assigned to the Linux kernel.
+ */
+Rm_PolicyValidInstNode *rmPolicyGetLinuxInstNode(Rm_Handle rmHandle)
+{
+ char linuxName[] = RM_ALLOCATED_TO_LINUX;
+
+ return (rmPolicyGetValidInstNode(rmHandle, linuxName));
+}
+
+/* FUNCTION PURPOSE: Validates resource permissions against a Policy DTB
+ ***********************************************************************
+ * DESCRIPTION: Returns TRUE if the instance name has the specified
+ * permissions for the specified resource in the Policy
+ * DTB. Otherwise, returns FALSE.
+ */
+int rmPolicyCheckPrivilege(Rm_PolicyCheckCfg *privilegeCfg, int32_t *result)
+{
+ int32_t propertyOffset;
+ const char *propertyName;
+ int32_t propertyLen;
+ const void *propertyData;
+ Rm_PolicyAssignment *assignment = NULL;
+ Rm_PolicyAssignment *assignmentStart = NULL;
+ Rm_PolicyPermission *permission = NULL;
+ Rm_PolicyPermission *permissionStart = NULL;
+ uint32_t assignmentEnd;
+ uint32_t resourceEnd = privilegeCfg->resourceBase + privilegeCfg->resourceLength - 1;
+ int foundInstance;
+
+ *result = RM_OK;
+
+ /* Get the resource's assignments */
+ propertyOffset = fdt_first_property_offset(privilegeCfg->policyDtb, privilegeCfg->resourceOffset);
+ if (propertyOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
+ while (propertyOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
+ propertyData = fdt_getprop_by_offset(privilegeCfg->policyDtb, propertyOffset, &propertyName, &propertyLen);
+ if (rmDtbUtilPolicyGetPropertyType(propertyName) == Rm_policyPropType_ASSIGNMENTS) {
+ assignment = assignmentStart = rmDtbUtilPolicyExtractAssignments(propertyData, propertyLen);
+ break;
+ }
+ propertyOffset = fdt_next_property_offset(privilegeCfg->policyDtb, propertyOffset);
+ }
+ }
+
+ if (assignment) {
+ while (assignment) {
+ assignmentEnd = assignment->resourceBase + assignment->resourceLength - 1;
+ foundInstance = RM_FALSE;
+ if (((privilegeCfg->resourceBase >= assignment->resourceBase) &&
+ (privilegeCfg->resourceBase <= assignmentEnd)) ||
+ ((privilegeCfg->resourceBase < assignment->resourceBase) &&
+ (resourceEnd > assignmentEnd)) ||
+ ((resourceEnd >= assignment->resourceBase) &&
+ (resourceEnd <= assignmentEnd))) {
+
+ permission = permissionStart = policyGetAssignmentPermissions(assignment, result);
+ while (permission) {
+ if ((strncmp(permission->instName, privilegeCfg->validInstNode->name, RM_NAME_MAX_CHARS) == 0) ||
+ (strncmp(permission->instName, Rm_policyAllInstances, RM_NAME_MAX_CHARS) == 0)) {
+ foundInstance = RM_TRUE;
+
+ /* Check instance's permissions */
+ if (privilegeCfg->type == Rm_policyCheck_INIT) {
+ if (!RM_policy_GET_PERM(permission->permissionBits, RM_POLICY_PERM_INIT_SHIFT)) {
+ policyFreeAssignmentPermissions(permissionStart);
+ rmDtbUtilPolicyFreeAssignments(assignmentStart);
+ return(RM_FALSE);
+ }
+ }
+ else if (privilegeCfg->type == Rm_policyCheck_USE) {
+ if (!RM_policy_GET_PERM(permission->permissionBits, RM_POLICY_PERM_USE_SHIFT)) {
+ policyFreeAssignmentPermissions(permissionStart);
+ rmDtbUtilPolicyFreeAssignments(assignmentStart);
+ return(RM_FALSE);
+ }
+ }
+ else if (privilegeCfg->type == Rm_policyCheck_EXCLUSIVE) {
+ if (!RM_policy_GET_PERM(permission->permissionBits, RM_POLICY_PERM_EXCLUSIVE_SHIFT)) {
+ policyFreeAssignmentPermissions(permissionStart);
+ rmDtbUtilPolicyFreeAssignments(assignmentStart);
+ return(RM_FALSE);
+ }
+ }
+ else if (privilegeCfg->type == Rm_policyCheck_SHARED_LINUX) {
+ if (!RM_policy_GET_PERM(permission->permissionBits, RM_POLICY_PERM_SHARED_LINUX_SHIFT)) {
+ policyFreeAssignmentPermissions(permissionStart);
+ rmDtbUtilPolicyFreeAssignments(assignmentStart);
+ return(RM_FALSE);
+ }
+ }
+ break;
+ }
+ permission = permission->nextPermission;
+ }
+
+ policyFreeAssignmentPermissions(permissionStart);
+ if (!foundInstance) {
+ rmDtbUtilPolicyFreeAssignments(assignmentStart);
+ return(RM_FALSE);
+ }
+ }
+ assignment = assignment->nextAssignment;
+ }
+ rmDtbUtilPolicyFreeAssignments(assignmentStart);
+ }
+ else {
+ return(RM_FALSE);
+ }
+
+ return(RM_TRUE);
+}
+
+/* FUNCTION PURPOSE: Returns resource base value according to the Policy
+ ***********************************************************************
+ * DESCRIPTION: Returns a resource base value based on the resource
+ * ranges assigned to the specified valid instance by the
+ * Policy DTB.
+ */
+uint32_t rmPolicyGetResourceBase(void *policyDtb, Rm_PolicyValidInstNode *validInstNode,
+ int32_t resourceOffset, Rm_PolicyCheckType policyCheckType,
+ int32_t *result)
+
+{
+ int32_t propertyOffset;
+ const char *propertyName;
+ int32_t propertyLen;
+ const void *propertyData;
+ Rm_PolicyAssignment *assignment = NULL;
+ Rm_PolicyAssignment *assignmentStart = NULL;
+ Rm_PolicyPermission *permission = NULL;
+ Rm_PolicyPermission *permissionStart = NULL;
+ uint32_t resourceBase = 0;
+
+ *result = RM_OK;
+
+ propertyOffset = fdt_first_property_offset(policyDtb, resourceOffset);
+ if (propertyOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
+ while (propertyOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
+ propertyData = fdt_getprop_by_offset(policyDtb, propertyOffset, &propertyName, &propertyLen);
+ if (rmDtbUtilPolicyGetPropertyType(propertyName) == Rm_policyPropType_ASSIGNMENTS) {
+ assignment = assignmentStart = rmDtbUtilPolicyExtractAssignments(propertyData, propertyLen);
+ break;
+ }
+ propertyOffset = fdt_next_property_offset(policyDtb, propertyOffset);
+ }
+ }
+
+ /* Search policy permissions for valid resource base */
+ while (assignment) {
+ permission = permissionStart = policyGetAssignmentPermissions(assignment, result);
+ while (permission) {
+ if ((strncmp(permission->instName, validInstNode->name, RM_NAME_MAX_CHARS) == 0) ||
+ (strncmp(permission->instName, Rm_policyAllInstances, RM_NAME_MAX_CHARS) == 0)) {
+ /* Check instance's permissions */
+ if ((policyCheckType == Rm_policyCheck_INIT) &&
+ RM_policy_GET_PERM(permission->permissionBits, RM_POLICY_PERM_INIT_SHIFT)) {
+ resourceBase = assignment->resourceBase;
+ break;
+ }
+ else if ((policyCheckType == Rm_policyCheck_USE) &&
+ RM_policy_GET_PERM(permission->permissionBits, RM_POLICY_PERM_USE_SHIFT)) {
+ resourceBase = assignment->resourceBase;
+ break;
+ }
+ }
+ permission = permission->nextPermission;
+ }
+ policyFreeAssignmentPermissions(permissionStart);
+
+ if (resourceBase != RM_RESOURCE_BASE_UNSPECIFIED) {
+ break;
+ }
+ else {
+ assignment = assignment->nextAssignment;
+ }
+ }
+
+ if (assignmentStart) {
+ rmDtbUtilPolicyFreeAssignments(assignmentStart);
+ }
+
+ return(resourceBase);
+}
+
+/* FUNCTION PURPOSE: Returns resource alignment value according to the Policy
+ ***********************************************************************
+ * DESCRIPTION: Parses the policy DTB to find and return a resource's
+ * alignment.
+ */
+uint32_t rmPolicyGetResourceAlignment(void *policyDtb, int32_t resourceOffset)
+{
+ int32_t propertyOffset;
+ const char *propertyName;
+ int32_t propertyLen;
+ const void *propertyData;
+ Rm_ResourceValue *alignmentList;
+ uint32_t resourceAlignment = 0;
+
+ propertyOffset = fdt_first_property_offset(policyDtb, resourceOffset);
+ if (propertyOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
+ while (propertyOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
+ propertyData = fdt_getprop_by_offset(policyDtb, propertyOffset, &propertyName, &propertyLen);
+ if (rmDtbUtilPolicyGetPropertyType(propertyName) == Rm_policyPropType_ALLOCATION_ALIGNMENT) {
+ alignmentList = rmDtbUtilPolicyExtractResourceAlignments(propertyData, propertyLen);
+ resourceAlignment = alignmentList->value;
+ rmDtbUtilPolicyFreeResourceAlignments(alignmentList);
+ }
+ propertyOffset = fdt_next_property_offset(policyDtb, propertyOffset);
+ }
+ }
+ return(resourceAlignment);
+}
+
+/* FUNCTION PURPOSE: Returns resource CD allocation size according to the Policy
+ ***********************************************************************
+ * DESCRIPTION: Parses the policy DTB to find and return a resource's
+ * allocation size.
+ */
+uint32_t rmPolicyGetResourceCdAllocSize(void *policyDtb, int32_t resourceOffset)
+{
+ int32_t propertyOffset;
+ const char *propertyName;
+ int32_t propertyLen;
+ const void *propertyData;
+ Rm_ResourceValue *allocSizeList;
+ uint32_t resourceAllocSize = 0;
+
+ propertyOffset = fdt_first_property_offset(policyDtb, resourceOffset);
+ if (propertyOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
+ while (propertyOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
+ propertyData = fdt_getprop_by_offset(policyDtb, propertyOffset, &propertyName, &propertyLen);
+ if (rmDtbUtilPolicyGetPropertyType(propertyName) == Rm_policyPropType_CD_ALLOCATION_SIZE) {
+ allocSizeList = rmDtbUtilPolicyExtractCdAllocationSizes(propertyData, propertyLen);
+ resourceAllocSize = allocSizeList->value;
+ rmDtbUtilPolicyFreeCdAllocationSizes(allocSizeList);
+ }
+ propertyOffset = fdt_next_property_offset(policyDtb, propertyOffset);
+ }
+ }
+ return(resourceAllocSize);
+}
+
+
+/* FUNCTION PURPOSE: Get a resource's offset into a Policy
+ ***********************************************************************
+ * DESCRIPTION: Returns the location of the specified resource node
+ * within the specified Policy in the form of an offset
+ * into the DTB. The resourceName and the Policy
+ * node name must match.
+ */
+int32_t rmPolicyGetResourceOffset(void *policyDtb, char *resourceName)
+{
+ int32_t nodeOffset;
+ int32_t depth;
+ const char *nodeName;
+
+ if (policyDtb) {
+ depth = RM_DTB_UTIL_STARTING_DEPTH;
+ nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;
+
+ /* Find node offset for provided resource name */
+ while ((nodeOffset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) &&
+ (depth >= RM_DTB_UTIL_STARTING_DEPTH)) {
+ nodeOffset = fdt_next_node(policyDtb, nodeOffset, &depth);
+ if (depth < RM_DTB_UTIL_STARTING_DEPTH) {
+ /* Resource name not found */
+ nodeOffset = RM_SERVICE_DENIED_RES_DOES_NOT_EXIST;
+ }
+ else {
+ nodeName = fdt_get_name(policyDtb, nodeOffset, NULL);
+ if (strncmp(nodeName, resourceName, RM_NAME_MAX_CHARS) == 0) {
+ break;
+ }
+ }
+ }
+ }
+ else {
+ nodeOffset = RM_ERROR_INSTANCE_HAS_NO_POLICY;
+ }
+ return(nodeOffset);
+}
+
+/* FUNCTION PURPOSE: Validates a Policy's resource node names
+ ***********************************************************************
+ * DESCRIPTION: Returns RM_OK if all of a Policy's resource node names
+ * match a node name specified in the "valid-instances"
+ * list specified at the top of the Policy. Otherwise,
+ * returns error
+ */
+int32_t rmPolicyValidatePolicyResourceNames(Rm_Handle rmHandle)
+{
+ void *policyDtb = rmPolicyGetPolicy(rmHandle);
+ int32_t nodeOffset;
+ int32_t depth;
+ const char *nodeName;
+
+ depth = RM_DTB_UTIL_STARTING_DEPTH;
+ nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;
+
+ /* Parse DTB, verifying each resource's assignment permissions.
+ * Permissions must have correct syntax and contain valid instance names
+ * according validInstList */
+ while ((nodeOffset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) &&
+ (depth >= RM_DTB_UTIL_STARTING_DEPTH)) {
+ nodeOffset = fdt_next_node(policyDtb, nodeOffset, &depth);
+ nodeName = fdt_get_name(policyDtb, nodeOffset, NULL);
+ if (fdt_first_property_offset(policyDtb, nodeOffset) > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
+ if (rmAllocatorFind(rmHandle, nodeName) == NULL) {
+ /* No allocator tied to resource name */
+ return(RM_ERROR_UNKNOWN_RESOURCE_IN_POLICY);
+ }
+ }
+ }
+ return(RM_OK);
+}
+
+/* FUNCTION PURPOSE: Validates a Policy DTB
+ ***********************************************************************
+ * DESCRIPTION: Returns RM_OK if the input Policy satisfies the
+ * following conditions:
+ * a) All "assignment" permission string parse okay
+ * b) All RM instance names specified in the permission
+ * strings match an instance name in the valid instance
+ * list
+ * c) All resource node names match a resource allocator
+ */
+int32_t rmPolicyValidatePolicy(Rm_Handle rmHandle)
+{
+ void *policyDtb = rmPolicyGetPolicy(rmHandle);
+ int32_t nodeOffset;
+ int32_t propertyOffset;
+ int32_t depth;
+ const char *propertyName;
+ int32_t propertyLen;
+ const void *propertyData;
+ Rm_PolicyPropType propertyType;
+ Rm_PolicyAssignment *assignmentList;
+ int32_t result;
+
+ depth = RM_DTB_UTIL_STARTING_DEPTH;
+ nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;
+
+ /* Parse DTB, verifying each resource's assignment permissions.
+ * Permissions must have correct syntax and contain valid instance names
+ * according validInstList */
+ while ((nodeOffset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) &&
+ (depth >= RM_DTB_UTIL_STARTING_DEPTH)) {
+ nodeOffset = fdt_next_node(policyDtb, nodeOffset, &depth);
+ propertyOffset = fdt_first_property_offset(policyDtb, nodeOffset);
+ while (propertyOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
+ propertyData = fdt_getprop_by_offset(policyDtb, propertyOffset, &propertyName, &propertyLen);
+ propertyType = rmDtbUtilPolicyGetPropertyType(propertyName);
+ if (propertyType == Rm_policyPropType_ASSIGNMENTS) {
+ assignmentList = rmDtbUtilPolicyExtractAssignments(propertyData, propertyLen);
+
+ if ((result = policyValidateAssignmentPermissions(rmHandle, assignmentList)) != RM_OK) {
+ rmDtbUtilPolicyFreeAssignments(assignmentList);
+ return(result);
+ }
+ rmDtbUtilPolicyFreeAssignments(assignmentList);
+ }
+ else if (propertyType == Rm_policyPropType_UNKNOWN) {
+ return(RM_ERROR_UNKNOWN_POLICY_RESOURCE_PROPERTY);
+ }
+ propertyOffset = fdt_next_property_offset(policyDtb, propertyOffset);
+ }
+ }
+ return(RM_OK);
+}
+
+/* FUNCTION PURPOSE: Creates the valid instance tree for a RM instance
+ ***********************************************************************
+ * DESCRIPTION: Creates the valid instance tree for a RM instance
+ * that has been provided a global or static policy
+ * The valid instance tree is created from the
+ * "valid-instances" property at the top of the Policy.
+ * The root entry of the valid instance tree is returned.
+ */
+Rm_PolicyValidInstTree *rmPolicyCreateValidInstTree(Rm_Handle rmHandle, int addLinux, int32_t *result)
+{
+ Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
+ void *policyDtb = rmPolicyGetPolicy(rmHandle);
+ int32_t validInstOffset;
+ const char *validInstName = NULL;
+ int32_t validInstLen;
+ const void *validInstData = NULL;
+ Rm_PolicyPropType propertyType;
+ Rm_PolicyValidInst *vInstListStart = NULL;
+ Rm_PolicyValidInst *validInstList = NULL;
+ Rm_PolicyValidInstTree *rootEntry = NULL;
+ Rm_PolicyValidInstNode *newNode = NULL;
+ char linuxName[] = RM_ALLOCATED_TO_LINUX;
+
+ /* Valid instance list must be first and only property in the root node of
+ * the policyDtb */
+ validInstOffset = fdt_first_property_offset(policyDtb, RM_DTB_UTIL_STARTING_NODE_OFFSET);
+ if (validInstOffset < -FDT_ERR_NOTFOUND) {
+ *result = validInstOffset;
+ return (NULL);
+ }
+ else if (validInstOffset == -FDT_ERR_NOTFOUND) {
+ *result = RM_ERROR_NO_VALID_INST_IN_POLICY;
+ return (NULL);
+ }
+ validInstData = fdt_getprop_by_offset(policyDtb, validInstOffset, &validInstName, &validInstLen);
+ propertyType = rmDtbUtilPolicyGetPropertyType(validInstName);
+ if (propertyType != Rm_policyPropType_VALID_INSTANCES) {
+ *result = RM_ERROR_NO_VALID_INST_IN_POLICY;
+ return (NULL);
+ }
+
+ if (!(validInstList = rmDtbUtilPolicyExtractValidInstances(validInstData, validInstLen, result))) {
+ return (NULL);
+ }
+
+ /* Create the tree */
+ rootEntry = Rm_osalMalloc(sizeof(Rm_PolicyValidInstTree));
+ RB_INIT(rootEntry);
+
+ vInstListStart = validInstList;
+ while (validInstList) {
+ newNode = rmPolicyValidInstNodeNew(validInstList->instName);
+ RB_INSERT(_Rm_PolicyValidInstTree, rootEntry, newNode);
+
+ validInstList = validInstList->nextValidInst;
+ }
+ rmDtbUtilPolicyFreeValidInstances(vInstListStart);
+
+ /* Add the Linux kernel node */
+ if (addLinux) {
+ newNode = rmPolicyValidInstNodeNew(linuxName);
+ RB_INSERT(_Rm_PolicyValidInstTree, rootEntry, newNode);
+ }
+
+ if (rmInst->instType == Rm_instType_SHARED_SERVER) {
+ /* Writeback the valid instance tree */
+ rmPolicyValidInstTreeWb(rootEntry);
+ }
+
+ *result = RM_OK;
+ return (rootEntry);
+}
+
+/* FUNCTION PURPOSE: Deletes a valid instance tree
+ ***********************************************************************
+ * DESCRIPTION: Frees all memory associated with a Policy valid
+ * instance tree.
+ */
+void rmPolicyFreeValidInstTree(Rm_Handle rmHandle)
+{
+ Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
+ Rm_PolicyValidInstTree *treeRoot = policyGetValidInstTree(rmHandle);
+ Rm_PolicyValidInstNode *node;
+ Rm_PolicyValidInstNode *nextNode;
+
+ if (treeRoot) {
+ if (rmInst->instType == Rm_instType_SHARED_SERVER) {
+ rmPolicyValidInstTreeInv(treeRoot);
+ }
+
+ for (node = RB_MIN(_Rm_PolicyValidInstTree, treeRoot); node != NULL; node = nextNode) {
+ nextNode = RB_NEXT(_Rm_PolicyValidInstTree, treeRoot, node);
+ RB_REMOVE(_Rm_PolicyValidInstTree, treeRoot, node);
+ rmPolicyValidInstNodeFree(node);
+ }
+
+ /* Don't need to writeback tree node changes since valid instance will be made
+ * NULL in instance */
+
+ if (RB_MIN(_Rm_PolicyValidInstTree, treeRoot) == NULL) {
+ /* No more valid instance nodes in tree */
+ Rm_osalFree((void *)treeRoot, sizeof(Rm_PolicyValidInstTree));
+ }
+
+ if ((rmInst->instType == Rm_instType_SERVER) ||
+ (rmInst->instType == Rm_instType_SHARED_SERVER)) {
+ rmInst->u.server.globalValidInstTree = NULL;
+ }
+ else if (rmInst->instType == Rm_instType_CLIENT_DELEGATE) {
+ rmInst->u.cd.cdValidInstTree = NULL;
+ }
+ else if (rmInst->instType == Rm_instType_CLIENT) {
+ rmInst->u.client.staticValidInstTree = NULL;
+ }
+ }
+}
+