Adding policy checking feature on RM Server
[keystone-rtos/rm-lld.git] / src / rm_policy.c
1 /**
2  *   @file  rmpolicy.c
3  *
4  *   @brief   
5  *      This is the Resource Manager Policy source.
6  *
7  *  \par
8  *  ============================================================================
9  *  @n   (C) Copyright 2012, 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 /* RM Types */
43 #include <ti/drv/rm/rm_types.h>
45 /* RM external API includes */
46 #include <ti/drv/rm/rm_policy.h>
47 #include <ti/drv/rm/rm_services.h>
49 /* RM internal API includes */
50 #include <ti/drv/rm/include/rm_loc.h>
51 #include <ti/drv/rm/include/rm_policyloc.h>
52 #include <ti/drv/rm/include/rm_dtb_utilloc.h>
54 /* RM LIBFDT includes */
55 #include <ti/drv/rm/src/libfdt/libfdt.h>
57 /* RM OSAL layer */
58 #include <rm_osal.h>
60 /**********************************************************************
61  ************** Red-Black BBST Tree NameServer Functions **************
62  **********************************************************************/
64 Rm_PolicyInstNode *Rm_newPolicyInstNode(const char *instName, int32_t nodeOffset)
65 {
66     Rm_PolicyInstNode *newNode = NULL;
68     newNode = Rm_osalMalloc(sizeof(Rm_PolicyInstNode));
70     /* Populate the node */
71     strcpy(newNode->instName, instName);
72     newNode->nodeOffset = nodeOffset;
73     
74     return(newNode);
75 }
77 void Rm_freePolicyInstNode(Rm_PolicyInstNode *node)
78 {
79     /* Free the memory associated with the tree node. */
80     Rm_osalFree((void *)node, sizeof(Rm_PolicyInstNode));
81 }
83 /* Prototype for tree node comparison function
84  * element1 < element2 --> return < 0
85  * element1 = element2 --> return 0
86  * element1 > element2 --> return > 0 */
87 int Rm_PolicyInstNodeCompare(Rm_PolicyInstNode *element1, Rm_PolicyInstNode *element2)
88 {
89     return(strcmp(element1->instName, element2->instName));
90 }
92 /* Generate the red-black tree manipulation functions */
93 RB_GENERATE(_Rm_PolicyInstLookupTree, _Rm_PolicyInstNode, linkage, Rm_PolicyInstNodeCompare);
95 /**********************************************************************
96  ********************** Internal Functions ****************************
97  **********************************************************************/
99 /* Function parses the policy DTB and saves the offset into the DTB for each
100  * RM instance name.  When services need to be checked against the policy the
101  * RM instance offset into the policy DTB can be retrieved from the lookup
102  * tree rather than reparsing the entire policy DTB */
103 void Rm_policyCreateInstanceLookup(Rm_PolicyData *policyDataPtr)
105     Rm_PolicyInstLookupTree *rootEntry = NULL;
106     Rm_PolicyInstNode *policyNode = NULL;  
107     Rm_PolicyInstNode *collidingNode = NULL;    
108     int32_t nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;
109     int32_t depth = RM_DTB_UTIL_STARTING_DEPTH;
110     const char *instName;
112     /* Create the policy instance lookup root entry and initialize it */
113     rootEntry = Rm_osalMalloc(sizeof(Rm_PolicyInstLookupTree));
114     RB_INIT(rootEntry);
116     policyDataPtr->instLookupTreeRoot = (void *)rootEntry;
118     /* Parse the entire policy DTB and store the node offsets that correspond to the root
119      * node for each RM instance. */
120     do
121     {
122         if (depth == RM_POLICY_DTB_INSTANCE_DEPTH)
123         {
124             instName = fdt_get_name(policyDataPtr->policyDtb, nodeOffset, NULL);
125             
126             /* Store the RM instance name and it's node offset into the policy DTB */
127             policyNode = Rm_newPolicyInstNode(instName, nodeOffset);
128             
129             /* Try to insert the new policy lookup node */
130             collidingNode = RB_INSERT(_Rm_PolicyInstLookupTree, 
131                                       policyDataPtr->instLookupTreeRoot, policyNode);
132             if (collidingNode)
133             {
134                 Rm_freePolicyInstNode(policyNode);
135             }            
136         }
137         
138         /* Get the next node */
139         nodeOffset = fdt_next_node(policyDataPtr->policyDtb, nodeOffset, &depth);
140     } while ((nodeOffset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) && (depth >= RM_DTB_UTIL_STARTING_DEPTH));
141    
142     /* TODO: ADD ERROR RETURN CODES */
145 int32_t Rm_policyCheck(Rm_PolicyHandle policyDtb, Rm_PolicyCheckInfo *checkInfo,
146                        Rm_PolicyNodeProperties *nodeProperties)
151 int32_t Rm_policyCheckResource(Rm_Inst *rmInst, Rm_PolicyCheckInfo *checkInfo)
153     Rm_PolicyData *policyDataPtr = (Rm_PolicyData *) rmInst->policyData;
154     Rm_PolicyInstNode findNode;
155     Rm_PolicyInstNode *matchingNode = NULL;
156     int32_t nodeOffset;
157     int32_t depth = RM_DTB_UTIL_STARTING_DEPTH;
158     const char *nodeName;
159     Rm_PolicyNodeProperties nodeProps;  
160         int32_t propertyLen;
161         const void *propertyData;
162     Rm_PolicyPropType propertyType;    
163     int32_t retVal = RM_SERVICE_PROCESSING;
165     /* Initialize the node properties to NULL */
166     memset((void *) &nodeProps, 0, sizeof(Rm_PolicyNodeProperties));
167     
168     /* Get the RM instance's node offset from the lookup tree */
169     strcpy(findNode.instName, checkInfo->serviceSrcInstName);
170     matchingNode = RB_FIND(_Rm_PolicyInstLookupTree, policyDataPtr->instLookupTreeRoot, &findNode);
172     if (matchingNode)
173     {
174         nodeOffset = matchingNode->nodeOffset;
175         nodeName = matchingNode->instName;        
177         /* Search for the resource node that matches the resource in the service request.
178          * Exit the search loop if the resource node is found or if all subnodes have been parsed
179          * without finding the resource (signalled by the depth being equivalent to the starting
180          * depth. */
181         while (strcmp(nodeName, checkInfo->resourceInfo->name))
182         {
183             /* Parse the nodes for the resource node.  All nodes should be subnodes of the
184              * found RM instance node.  Therefore, the depth should be greater than the
185              * starting depth */
186             nodeOffset = fdt_next_node(policyDataPtr->policyDtb, nodeOffset, &depth);
187             
188             if ((depth <= RM_DTB_UTIL_STARTING_DEPTH) || (nodeOffset <= -FDT_ERR_NOTFOUND))
189             {
190                 retVal = RM_SERVICE_DENIED_RESOURCE_NOT_DEFINED_IN_POLICY;
191                 break;
192             }  
193             
194             nodeName = fdt_get_name(policyDataPtr->policyDtb, nodeOffset, NULL);         
195         }
197         if (retVal == RM_SERVICE_PROCESSING)
198         {
199             /* Get the resource node's properties */
201             /* Get the properties for the resource node if any exist */
202             nodeOffset = fdt_first_property_offset(policyDataPtr->policyDtb, nodeOffset);
204             while ((nodeOffset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) && (retVal == RM_SERVICE_PROCESSING))
205             {
206                 /* Get the property data and store it in the corresponding nodeProps field */
207                     propertyData = fdt_getprop_by_offset(policyDataPtr->policyDtb, nodeOffset, 
208                                                          &nodeName, &propertyLen);
210                 propertyType = Rm_policyGetPropertyType(nodeName);
211                 if (propertyType == Rm_policyPropType_ASSIGNED_RANGES)
212                 {
213                     if (nodeProps.rangeData || nodeProps.rangeLen)
214                     {
215                         /* The range fields have already been populated.  Return an error.
216                          * The policy has specified a property field more than once
217                          * for a resource node */
218                         retVal = RM_SERVICE_DENIED_ASSIGNED_RANGE_SPECIFICATION_ERROR;
219                     }
220                     else
221                     {
222                         nodeProps.rangeData = propertyData;
223                         nodeProps.rangeLen = propertyLen;
224                     }
225                 }
226                 else if (propertyType == Rm_policyPropType_ALLOCATION_SIZES)
227                 {
228                     if (nodeProps.allocationSizeData || nodeProps.allocationSizeLen)
229                     {
230                         /* The allocationSize fields have already been populated.  Return an error.
231                          * The policy has specified a property field more than once
232                          * for a resource node */
233                         retVal = RM_SERVICE_DENIED_ALLOCATION_SIZE_SPECIFICATION_ERROR;
234                     }
235                     else
236                     {
237                         nodeProps.allocationSizeData = propertyData;
238                         nodeProps.allocationSizeLen = propertyLen;
239                     }
240                 }
241                 else if (propertyType == Rm_policyPropType_ASSIGNED_NAMES)
242                 {
243                     if (nodeProps.assignedNamesData || nodeProps.assignedNamesLen)
244                     {
245                         /* The assignedNames fields have already been populated.  Return an error.
246                          * The policy has specified a property field more than once
247                          * for a resource node */
248                         retVal = RM_SERVICE_DENIED_ASSIGNED_NAME_SPECIFICATION_ERROR;
249                     }
250                     else
251                     {
252                         nodeProps.assignedNamesData = propertyData;
253                         nodeProps.assignedNamesLen = propertyLen;
254                     }
255                 }        
256                 else if (propertyType == Rm_policyPropType_ALLOCATION_ALIGNMENTS)
257                 {
258                     if (nodeProps.alignmentData || nodeProps.alignmentLen)
259                     {
260                         /* The alignment fields have already been populated.  Return an error.
261                          * The policy has specified a property field more than once
262                          * for a resource node */
263                         retVal = RM_SERVICE_DENIED_ALLOCATION_ALIGNMENT_SPECIFICATION_ERROR;
264                     }
265                     else
266                     {
267                         nodeProps.alignmentData = propertyData;
268                         nodeProps.alignmentLen = propertyLen;
269                     }
270                 }                  
271                 else
272                 {
273                     retVal = RM_SERVICE_DENIED_UNKNOWN_POLICY_PROPERTY;
274                 }
276                 nodeOffset = fdt_next_property_offset(policyDataPtr->policyDtb, nodeOffset);
277             }
278         }
280         if (retVal == RM_SERVICE_PROCESSING)
281         {
282             /* Check the resource(s) in the service request against what is assigned to 
283              * the instance */
284             retVal = Rm_policyCheck(policyDataPtr->policyDtb, checkInfo, &nodeProps);
285         }
286     }
287     else
288     {
289         /* RM instance not defined in policy.  Service denied */
290         retVal = RM_SERVICE_DENIED_RM_INST_NOT_DEFINED_IN_POLICY;
291     }    
293     return(retVal);
296 void Rm_policyInit(Rm_Inst *rmInst, void *policyDtb)
298     Rm_PolicyData *policyDataPtr;
299     
300     /* Allocate memory for the policy data structure */
301     policyDataPtr = Rm_osalMalloc(sizeof(Rm_PolicyData));
302     
303     /* Open the policy DTB and create the instance node offset lookup table */
304     fdt_open_into(policyDtb, policyDtb, fdt_totalsize(policyDtb));
305     policyDataPtr->policyDtb = policyDtb;
306     Rm_policyCreateInstanceLookup(policyDataPtr);
308     /* Store the policy in the RM instance */
309     rmInst->policyData = (void *) policyDataPtr;