1 /**
2 * @file rm.c
3 *
4 * @brief
5 * This is the Resource Manager source.
6 *
7 * \par
8 * ============================================================================
9 * @n (C) Copyright 2012-2013, Texas Instruments, Inc.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 *
15 * Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 *
18 * Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the
21 * distribution.
22 *
23 * Neither the name of Texas Instruments Incorporated nor the names of
24 * its contributors may be used to endorse or promote products derived
25 * from this software without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
31 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
32 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
33 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
37 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 *
39 * \par
40 */
42 /* Standard includes */
43 #include <stdint.h>
44 #include <string.h>
45 #include <stdbool.h>
47 /* RM external includes */
48 #include <ti/drv/rm/rm.h>
49 #include <ti/drv/rm/rmver.h>
50 #include <ti/drv/rm/rm_services.h>
51 #include <ti/drv/rm/rm_transport.h>
53 /* RM internal includes */
54 #include <ti/drv/rm/include/rm_loc.h>
55 #include <ti/drv/rm/include/rm_transportloc.h>
56 #include <ti/drv/rm/include/rm_nameserverloc.h>
57 #include <ti/drv/rm/include/rm_dtb_utilloc.h>
58 #include <ti/drv/rm/include/rm_policyloc.h>
59 #include <ti/drv/rm/include/rm_treeloc.h>
61 /* RM LIBFDT includes */
62 #include <ti/drv/rm/util/libfdt/libfdt.h>
64 /* Tree algorithm includes */
65 #include <ti/drv/rm/util/tree.h>
67 /* RM OSAL layer */
68 #include <rm_osal.h>
70 /**********************************************************************
71 ************************** Globals ***********************************
72 **********************************************************************/
74 /** @brief Global Variable which describes the RM Version Information */
75 const char rmVersionStr[] = RM_VERSION_STR ":" __DATE__ ":" __TIME__;
77 /**********************************************************************
78 ************************ Local Functions *****************************
79 **********************************************************************/
81 /* FUNCTION PURPOSE: Initializes a RM inst's transaction sequence number
82 ***********************************************************************
83 * DESCRIPTION: The RM instance transaction sequence number can never
84 * have a value of 0 to avoid conflicts with transactions
85 * that have a remoteOriginatingId of 0 (transaction ID
86 * will be used as the remoteOriginatingId for
87 * transactions that are responses to requests).
88 */
89 static uint32_t transactionInitSequenceNum(void)
90 {
91 return (1);
92 }
94 /* FUNCTION PURPOSE: Provides a sequence number for new transactions
95 ***********************************************************************
96 * DESCRIPTION: Returns a sequence number for a new transaction
97 * specific to a RM instance. Handles rollover of
98 * sequence number.
99 */
100 static uint32_t transactionGetSequenceNum(Rm_Inst *rmInst)
101 {
102 rmInst->transactionSeqNum++;
103 if (!rmInst->transactionSeqNum) {
104 rmInst->transactionSeqNum++;
105 }
106 return (rmInst->transactionSeqNum);
107 }
109 /* FUNCTION PURPOSE: Creates a resource allocator
110 ***********************************************************************
111 * DESCRIPTION: Returns a newly Created and initialized resource
112 * The allocator is also stored in the RM instance
113 * allocator list.
114 */
115 static Rm_Allocator *allocatorAdd(Rm_Inst *rmInst, const char *resourceName)
116 {
117 Rm_Allocator *allocators = rmInst->allocators;
118 Rm_Allocator *newAllocator = NULL;
120 newAllocator = Rm_osalMalloc(sizeof(Rm_Allocator));
122 if (newAllocator) {
123 memset((void *)newAllocator, 0, sizeof(Rm_Allocator));
124 strncpy(newAllocator->resourceName, resourceName, RM_NAME_MAX_CHARS);
125 newAllocator->allocatorRootEntry = NULL;
126 newAllocator->nextAllocator = NULL;
128 /* Add allocator to end of list */
129 if (allocators) {
130 while (allocators->nextAllocator) {
131 allocators = allocators->nextAllocator;
132 }
133 allocators->nextAllocator = newAllocator;
134 }
135 else {
136 rmInst->allocators = newAllocator;
137 }
138 }
139 return (newAllocator);
140 }
142 /* FUNCTION PURPOSE: Deletes a resource allocator
143 ***********************************************************************
144 * DESCRIPTION: Deletes a resource allocator based on the given
145 * resource name. The resource allocator will be
146 * removed from the RM instance allocator list.
147 */
148 static int32_t allocatorDelete(Rm_Inst *rmInst, char *resourceName)
149 {
150 Rm_Allocator *allocator = rmInst->allocators;
151 Rm_Allocator *prevAllocator = NULL;
152 int32_t retVal = RM_OK;
154 while (allocator) {
155 if (strncmp(allocator->resourceName, resourceName, RM_NAME_MAX_CHARS) == 0) {
156 break;
157 }
158 prevAllocator = allocator;
159 allocator = allocator->nextAllocator;
160 }
162 if (allocator) {
163 if (prevAllocator == NULL) {
164 rmInst->allocators = allocator->nextAllocator;
165 }
166 else {
167 prevAllocator->nextAllocator = allocator->nextAllocator;
168 }
169 Rm_osalFree((void *)allocator, sizeof(Rm_Allocator));
170 }
171 else {
172 retVal = RM_ERROR_RES_ALLOCATOR_DOES_NOT_EXIST;
173 }
174 return (retVal);
175 }
177 /* FUNCTION PURPOSE: Adds an owner to an allocator resource
178 ***********************************************************************
179 * DESCRIPTION: Adds a RM instance node to a resource node's
180 * list of owners.
181 */
182 static void addOwner(Rm_ResourceNode *node, void *serviceInstNode)
183 {
184 Rm_Owner *ownerList = node->ownerList;
185 Rm_Owner *newOwner = NULL;
187 newOwner = Rm_osalMalloc(sizeof(Rm_Owner));
189 if (newOwner) {
190 newOwner->instNameNode = serviceInstNode;
191 newOwner->nextOwner = NULL;
193 /* Add owner entry to end of list */
194 if (ownerList) {
195 while (ownerList->nextOwner) {
196 ownerList = ownerList->nextOwner;
197 }
198 ownerList->nextOwner = newOwner;
199 }
200 else {
201 node->ownerList = newOwner;
202 }
204 node->allocationCount++;
205 newOwner->instNameNode->allocRefCount++;
206 }
207 }
209 /* FUNCTION PURPOSE: Checks a resource node's ownership
210 ***********************************************************************
211 * DESCRIPTION: Returns TRUE if the provided instance node is
212 * in the list of resource node owners. Otherwise,
213 * returns FALSE.
214 */
215 static bool isOwnedBy(Rm_ResourceNode *node, void *serviceInstNode)
216 {
217 Rm_Owner *owner = node->ownerList;
219 while (owner) {
220 if (owner->instNameNode == serviceInstNode) {
221 return(true);
222 }
223 owner = owner->nextOwner;
224 }
225 return(false);
226 }
228 /* FUNCTION PURPOSE: Compares two resource node's owners
229 ***********************************************************************
230 * DESCRIPTION: Returns TRUE if the owners of two resource nodes
231 * are equivalent. Otherwise, returns FALSE.
232 */
233 static bool compareResourceNodeOwners(Rm_ResourceNode *node1, Rm_ResourceNode *node2)
234 {
235 Rm_Owner *node1Owners = node1->ownerList;
236 Rm_Owner *node2Owners = node2->ownerList;
237 bool matchedInst;
239 if (node1->allocationCount == node2->allocationCount) {
240 while (node1Owners) {
241 matchedInst = false;
242 while (node2Owners) {
243 if (node1Owners->instNameNode == node2Owners->instNameNode) {
244 matchedInst = true;
245 break;
246 }
247 node2Owners = node2Owners->nextOwner;
248 }
250 if (matchedInst) {
251 node2Owners = node2->ownerList;
252 node1Owners = node1Owners->nextOwner;
253 }
254 else {
255 return(false);
256 }
257 }
258 }
259 else {
260 return(false);
261 }
263 return(true);
264 }
266 /* FUNCTION PURPOSE: Deletes an owner from an allocator resource
267 ***********************************************************************
268 * DESCRIPTION: Removes a RM instance node from a resource node's
269 * list of owners.
270 */
271 static void deleteOwner(Rm_ResourceNode *node, void *serviceInstNode)
272 {
273 Rm_Owner *owner = node->ownerList;
274 Rm_Owner *prevOwner = NULL;
276 while (owner) {
277 if (owner->instNameNode == serviceInstNode) {
278 break;
279 }
280 prevOwner = owner;
281 owner = owner->nextOwner;
282 }
284 if (prevOwner == NULL) {
285 node->ownerList = owner->nextOwner;
286 }
287 else {
288 prevOwner->nextOwner = owner->nextOwner;
289 }
291 node->allocationCount--;
292 owner->instNameNode->allocRefCount--;
293 Rm_osalFree((void *)owner, sizeof(Rm_Owner));
294 }
296 /* FUNCTION PURPOSE: Copies the owners of a resource node
297 ***********************************************************************
298 * DESCRIPTION: Creates a list of resource owners for the destination
299 * resource node that is equivalent to the the
300 * source resource node's owners
301 */
302 static void copyOwners(Rm_ResourceNode *dstNode, Rm_ResourceNode *srcNode)
303 {
304 Rm_Owner *srcOwnerList = srcNode->ownerList;
305 Rm_Owner *dstNewOwner;
306 Rm_Owner *dstPrevOwner;
308 dstNode->allocationCount = srcNode->allocationCount;
310 while (srcOwnerList) {
311 dstNewOwner = Rm_osalMalloc(sizeof(Rm_Owner));
312 dstNewOwner->instNameNode = srcOwnerList->instNameNode;
313 dstNewOwner->nextOwner = NULL;
315 if (dstNode->ownerList == NULL) {
316 dstNode->ownerList = dstNewOwner;
317 }
318 else {
319 dstPrevOwner->nextOwner = dstNewOwner;
320 }
321 dstPrevOwner = dstNewOwner;
322 srcOwnerList = srcOwnerList->nextOwner;
323 }
324 }
326 /* FUNCTION PURPOSE: Clears a resource node's owners
327 ***********************************************************************
328 * DESCRIPTION: Deletes all owners from the owners list of a
329 * resource node.
330 */
331 static void clearOwners(Rm_ResourceNode *node)
332 {
333 Rm_Owner *owner = node->ownerList;
334 Rm_Owner *nextOwner;
336 while (owner) {
337 nextOwner = owner->nextOwner;
338 node->allocationCount--;
339 Rm_osalFree((void *)owner, sizeof(Rm_Owner));
340 owner = nextOwner;
341 }
342 }
344 /* FUNCTION PURPOSE: Creates a new resource tree
345 ***********************************************************************
346 * DESCRIPTION: Creates a new resource tree using the provided
347 * resource name and value range. The name and value
348 * typically originate from the GRL.
349 */
350 static int32_t createResourceTree(Rm_Inst *rmInst, const char *resourceName, Rm_ResourceRange *range)
351 {
352 Rm_Allocator *allocator = NULL;
353 Rm_ResourceTree *treeRootEntry = NULL;
354 Rm_ResourceNode *treeNode = NULL;
355 Rm_ResourceNode *collidingNode = NULL;
357 allocator = allocatorAdd(rmInst, resourceName);
358 treeRootEntry = Rm_osalMalloc(sizeof(Rm_ResourceTree));
359 RB_INIT(treeRootEntry);
361 while (range != NULL) {
362 treeNode = rmResourceNodeNew(range->base, range->length);
363 collidingNode = RB_INSERT(_Rm_AllocatorResourceTree, treeRootEntry, treeNode);
365 if (collidingNode) {
366 Rm_ResourceNode *nextNode = NULL;
368 /* Node that was inserted collides with existing node. Destroy tree and return error */
369 for (treeNode = RB_MIN(_Rm_AllocatorResourceTree, treeRootEntry); treeNode != NULL; treeNode = nextNode) {
370 nextNode = RB_NEXT(_Rm_AllocatorResourceTree, treeRootEntry, treeNode);
371 RB_REMOVE(_Rm_AllocatorResourceTree, treeRootEntry, nextNode);
372 rmResourceNodeFree(treeNode);
373 }
374 Rm_osalFree((void *)treeRootEntry, sizeof(Rm_ResourceTree));
375 allocatorDelete(rmInst, allocator->resourceName);
376 return (RM_ERROR_GRL_RES_SPECIFIED_MORE_THAN_ONCE);
377 }
378 range = range->nextRange;
379 }
381 allocator->allocatorRootEntry = treeRootEntry;
382 return(RM_OK);
383 }
385 /* FUNCTION PURPOSE: Preallocates a resource
386 ***********************************************************************
387 * DESCRIPTION: Called when an allocate request is made but the base
388 * is unspecified. The preallocation algorithm looks at
389 * available resources as well as policy permissions to
390 * determine a resource range that satisfies the request.
391 * If a valid range is found it will be returned for the
392 * treeAllocate algorithm to handle.
393 */
394 static int32_t treePreAllocate(Rm_Inst *rmInst, Rm_Allocator *allocator, int32_t resourcePolicy,
395 Rm_AllocatorOpInfo *opInfo)
396 {
397 Rm_ResourceNode findNode;
398 Rm_ResourceNode *matchingNode = NULL;
399 uint32_t matchingEnd;
400 uint32_t rangeIndex;
401 bool resourceFound = false;
402 Rm_PolicyCheckType policyCheckType;
403 Rm_PolicyCheckCfg policyCheckCfg;
404 bool nodePassesPolicy;
405 int32_t retVal = RM_SERVICE_PROCESSING;
407 opInfo->resourceInfo->base = rmPolicyGetResourceBase(rmInst->policy, opInfo->serviceSrcInstNode,
408 resourcePolicy, opInfo->allocType,
409 &retVal);
410 if (retVal != RM_SERVICE_PROCESSING) {
411 return (retVal);
412 }
414 if (opInfo->resourceInfo->alignment == RM_RESOURCE_ALIGNMENT_UNSPECIFIED) {
415 /* Get alignment from policy */
416 opInfo->resourceInfo->alignment = rmPolicyGetResourceAlignment(rmInst->policy, resourcePolicy);
417 }
419 if (opInfo->resourceInfo->alignment == 0) {
420 opInfo->resourceInfo->alignment = 1;
421 }
423 memset((void *)&findNode, 0, sizeof(Rm_ResourceNode));
424 findNode.base = opInfo->resourceInfo->base;
425 findNode.length = opInfo->resourceInfo->length;
427 /* Configure policy checking structure */
428 memset((void *)&policyCheckCfg, 0, sizeof(Rm_PolicyCheckCfg));
429 if (RM_policy_GET_PERM(opInfo->allocType, RM_POLICY_PERM_INIT_SHIFT)) {
430 policyCheckType = Rm_policyCheck_INIT;
431 }
432 else if (RM_policy_GET_PERM(opInfo->allocType, RM_POLICY_PERM_USE_SHIFT)) {
433 policyCheckType = Rm_policyCheck_USE;
434 }
435 policyCheckCfg.policyDtb = rmInst->policy;
436 policyCheckCfg.resourceOffset = resourcePolicy;
438 do {
439 matchingNode = RB_FIND(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, &findNode);
441 if (matchingNode) {
442 nodePassesPolicy = false;
443 policyCheckCfg.type = policyCheckType;
444 policyCheckCfg.validInstNode = opInfo->serviceSrcInstNode;
445 policyCheckCfg.resourceBase = findNode.base;
446 policyCheckCfg.resourceLength = findNode.length;
447 nodePassesPolicy = rmPolicyCheckPrivilege(&policyCheckCfg, &retVal);
449 if (nodePassesPolicy && (matchingNode->allocationCount > 0)) {
450 /* Check exclusive privileges of instance requesting resource. Requesting
451 * instance with exclusive privileges can't reserve resource if already owned*/
452 policyCheckCfg.type = Rm_policyCheck_EXCLUSIVE;
453 policyCheckCfg.validInstNode = opInfo->serviceSrcInstNode;
454 nodePassesPolicy = !rmPolicyCheckPrivilege(&policyCheckCfg, &retVal);
455 }
457 if (nodePassesPolicy && (matchingNode->allocationCount == 1)) {
458 /* Check exclusive privileges of instance that currently owns resource */
459 policyCheckCfg.type = Rm_policyCheck_EXCLUSIVE;
460 policyCheckCfg.validInstNode = matchingNode->ownerList->instNameNode;
461 nodePassesPolicy = !rmPolicyCheckPrivilege(&policyCheckCfg, &retVal);
462 }
464 if (retVal != RM_SERVICE_PROCESSING) {
465 break;
466 }
468 if (nodePassesPolicy) {
469 matchingEnd = matchingNode->base + matchingNode->length - 1;
470 /* Initialize indexer to be first resource value that alignment */
471 rangeIndex = findNode.base;
472 if (rangeIndex % opInfo->resourceInfo->alignment) {
473 rangeIndex += (opInfo->resourceInfo->alignment -
474 (rangeIndex % opInfo->resourceInfo->alignment));
475 }
477 if ((rangeIndex + opInfo->resourceInfo->length - 1) <= matchingEnd) {
478 /* Block of unallocated resources within matchingNode that satisfies
479 * allocate requirements */
480 opInfo->resourceInfo->base = rangeIndex;
481 resourceFound = true;
482 }
483 }
485 if (!resourceFound) {
486 /* Check next resource node for available resources */
487 findNode.base = matchingNode->base + matchingNode->length;
488 }
489 }
490 else {
491 retVal = RM_SERVICE_DENIED_RES_ALLOC_REQS_NOT_MET;
492 }
493 } while ((!resourceFound) &&
494 (retVal != RM_SERVICE_DENIED_RES_ALLOC_REQS_NOT_MET));
496 return(retVal);
497 }
499 /* FUNCTION PURPOSE: Allocates a resource
500 ***********************************************************************
501 * DESCRIPTION: Will attempt to allocate the resource with specified
502 * base and length from the resource's allocator. The
503 * allocation algorithm will verify the allocation against
504 * the policy permissions for the instance requesting the
505 * allocation. If the policy allows the allocation the
506 * algorithm will allocate the resource then combine any
507 * resource nodes that may have become equivalent (in terms
508 * of ownership) after the allocation.
509 */
510 static int32_t treeAllocate(Rm_Inst *rmInst, Rm_Allocator *allocator, int32_t resourcePolicy,
511 Rm_AllocatorOpInfo *opInfo)
512 {
513 Rm_ResourceNode findNode;
514 Rm_ResourceNode *matchingNode = NULL;
515 Rm_ResourceNode *leftNode = NULL;
516 Rm_ResourceNode *rightNode = NULL;
517 Rm_PolicyCheckType policyCheckType;
518 Rm_PolicyCheckCfg policyCheckCfg;
519 bool allocPassesPolicy;
520 bool combineLeft = false;
521 bool combineRight = false;
522 uint32_t findEnd;
523 uint32_t matchingEnd;
524 int32_t retVal = RM_SERVICE_PROCESSING;
526 memset((void *)&findNode, 0, sizeof(Rm_ResourceNode));
527 findNode.base = opInfo->resourceInfo->base;
528 findNode.length = opInfo->resourceInfo->length;
529 matchingNode = RB_FIND(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, &findNode);
531 /* Prepare privilege checks */
532 memset((void *)&policyCheckCfg, 0, sizeof(Rm_PolicyCheckCfg));
533 if (RM_policy_GET_PERM(opInfo->allocType, RM_POLICY_PERM_INIT_SHIFT)) {
534 policyCheckType = Rm_policyCheck_INIT;
535 }
536 else if (RM_policy_GET_PERM(opInfo->allocType, RM_POLICY_PERM_USE_SHIFT)) {
537 policyCheckType = Rm_policyCheck_USE;
538 }
540 if (matchingNode) {
541 findEnd = findNode.base + findNode.length - 1;
542 matchingEnd = matchingNode->base + matchingNode->length - 1;
544 if ((findNode.base >= matchingNode->base) && (findEnd <= matchingEnd)) {
545 if (opInfo->serviceSrcInstNode == rmPolicyGetLinuxInstNode(rmInst->validInstances)) {
546 /* Bypass policy checks since Linux Kernel has full privileges */
547 allocPassesPolicy = true;
548 }
549 else {
550 policyCheckCfg.policyDtb = rmInst->policy;
551 policyCheckCfg.resourceOffset = resourcePolicy;
552 policyCheckCfg.type = policyCheckType;
553 policyCheckCfg.validInstNode = opInfo->serviceSrcInstNode;
554 policyCheckCfg.resourceBase = findNode.base;
555 policyCheckCfg.resourceLength = findNode.length;
556 allocPassesPolicy = rmPolicyCheckPrivilege(&policyCheckCfg, &retVal);
557 if (!allocPassesPolicy) {
558 if (policyCheckType == Rm_policyCheck_INIT) {
559 retVal = RM_SERVICE_DENIED_INIT_PERM_NOT_GIVEN;
560 }
561 else {
562 retVal = RM_SERVICE_DENIED_USE_PERM_NOT_GIVEN;
563 }
564 }
566 if (!isOwnedBy(matchingNode, opInfo->serviceSrcInstNode)) {
567 /* Perform exclusive checks if requesting instance does not already an
568 * owner of the resource */
569 if (allocPassesPolicy && (matchingNode->allocationCount > 0)) {
570 /* Check exclusive privileges of instance requesting resource. Requesting
571 * instance with exclusive privileges can't reserve resource if already owned*/
572 policyCheckCfg.type = Rm_policyCheck_EXCLUSIVE;
573 policyCheckCfg.validInstNode = opInfo->serviceSrcInstNode;
574 allocPassesPolicy = !rmPolicyCheckPrivilege(&policyCheckCfg, &retVal);
575 if (!allocPassesPolicy) {
576 retVal = RM_SERVICE_DENIED_EXCLUSIVE_RES_ALLOCD;
577 }
578 }
579 if (allocPassesPolicy && (matchingNode->allocationCount == 1)) {
580 /* Check exclusive privileges of instance that currently owns resource */
581 policyCheckCfg.type = Rm_policyCheck_EXCLUSIVE;
582 policyCheckCfg.validInstNode = matchingNode->ownerList->instNameNode;
583 allocPassesPolicy = !rmPolicyCheckPrivilege(&policyCheckCfg, &retVal);
584 if (!allocPassesPolicy) {
585 retVal = RM_SERVICE_DENIED_ALLOCD_TO_EXCLUSIVE_INST;
586 }
587 }
588 }
589 }
591 if (allocPassesPolicy) {
592 if (!isOwnedBy(matchingNode, opInfo->serviceSrcInstNode)) {
593 /* Handle any possible node combinations if requesting instance is
594 * not already in resource's owner list. Automatic approval if requesting
595 * instance is already in owner list. */
596 if ((findNode.base == matchingNode->base) && (findEnd == matchingEnd)) {
597 /* findNode range matches matchingNode range
598 *
599 * |<--left node-->||<--matched node-->||<--right node-->| => existing node
600 * |<--alloc request-->| => requested resources
601 */
602 leftNode = RB_PREV(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
603 rightNode = RB_NEXT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
604 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
605 addOwner(matchingNode, opInfo->serviceSrcInstNode);
607 if (leftNode && compareResourceNodeOwners(leftNode, matchingNode)) {
608 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
609 combineLeft = true;
610 }
611 if (rightNode && compareResourceNodeOwners(rightNode, matchingNode)) {
612 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
613 combineRight = true;
614 }
616 if (combineLeft && combineRight) {
617 /* Combine all three nodes into matchingNode */
618 matchingNode->base = leftNode->base;
619 matchingNode->length = leftNode->length + matchingNode->length + rightNode->length;
621 clearOwners(leftNode);
622 rmResourceNodeFree(leftNode);
623 clearOwners(rightNode);
624 rmResourceNodeFree(rightNode);
625 }
626 else if (combineLeft) {
627 /* Combine left and matching nodes. Reinsert right. */
628 matchingNode->base = leftNode->base;
629 matchingNode->length += leftNode->length;
631 clearOwners(leftNode);
632 rmResourceNodeFree(leftNode);
633 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
634 }
635 else if (combineRight) {
636 /* Combine right and matching nodes. Reinsert left. */
637 matchingNode->length += rightNode->length;
639 clearOwners(rightNode);
640 rmResourceNodeFree(rightNode);
641 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
642 }
643 else {
644 /* No combine. */
645 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
646 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
647 }
649 /* Always reinsert matchingNode */
650 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
651 }
652 else if ((findNode.base > matchingNode->base) && (findEnd < matchingEnd)) {
653 /* findNode range is subset of matchingNode range and neither boundary is
654 * equivalent.
655 *
656 * |<----------matched node---------->|
657 * |<---alloc request--->|
658 */
659 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
660 leftNode = rmResourceNodeNew(matchingNode->base, findNode.base - matchingNode->base);
661 copyOwners(leftNode, matchingNode);
662 rightNode = rmResourceNodeNew(findNode.base + findNode.length, matchingEnd - findEnd);
663 copyOwners(rightNode, matchingNode);
665 matchingNode->base = findNode.base;
666 matchingNode->length = findNode.length;
667 addOwner(matchingNode, opInfo->serviceSrcInstNode);
669 /* Insert all the nodes */
670 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
671 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
672 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
673 }
674 else {
675 if (findNode.base == matchingNode->base) {
676 /* findNode base and matchingNode base are equivalent. May be combine
677 * possibilities to the left
678 *
679 * |<---left node (alloc'd)--->||<----------matched node---------->|
680 * |<---findNode (alloc req)--->|
681 */
682 leftNode = RB_PREV(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
683 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
684 /* Add allocating instance to owner list for compare with leftNode */
685 addOwner(matchingNode, opInfo->serviceSrcInstNode);
687 if (leftNode && compareResourceNodeOwners(leftNode, matchingNode)) {
688 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
689 /* Combine leftNode and findNode */
690 leftNode->length += findNode.length;
691 }
692 else {
693 leftNode = rmResourceNodeNew(findNode.base, findNode.length);
694 copyOwners(leftNode, matchingNode);
695 }
697 /* Account for leftNode in matchingNode */
698 matchingNode->base = findNode.base + findNode.length;
699 matchingNode->length = matchingEnd - findEnd;
701 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
702 }
703 else if (findEnd == matchingEnd) {
704 /* findNode end and matchingNode end are equivalent. May be combine
705 * possibilities to the right
706 *
707 * |<----------matched node---------->||<---right node (alloc'd)--->|
708 * |<---findNode (alloc req)--->|
709 */
710 rightNode = RB_NEXT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
711 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
712 /* Add allocating instance to owner list for compare with rightNode */
713 addOwner(matchingNode, opInfo->serviceSrcInstNode);
715 if (rightNode && compareResourceNodeOwners(rightNode, matchingNode)) {
716 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
717 /* Combine rightNode and findNode */
718 rightNode->base = findNode.base;
719 rightNode->length += findNode.length;
720 }
721 else {
722 rightNode = rmResourceNodeNew(findNode.base, findNode.length);
723 copyOwners(rightNode, matchingNode);
724 }
726 /* Account for rightNode in matchingNode */
727 matchingNode->length -= findNode.length;
729 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
730 }
731 /* Remove allocating instance from leftover matchingNode */
732 deleteOwner(matchingNode, opInfo->serviceSrcInstNode);
733 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
734 }
735 }
736 retVal = RM_SERVICE_APPROVED;
737 }
738 }
739 else {
740 retVal = RM_SERVICE_DENIED_PARTIAL_ALLOCATION;
741 }
742 }
743 else {
744 retVal = RM_SERVICE_DENIED_RES_RANGE_DOES_NOT_EXIST;
745 }
747 return(retVal);
748 }
750 /* FUNCTION PURPOSE: Frees a resource
751 ***********************************************************************
752 * DESCRIPTION: Will attempt to free the resource with specified
753 * base and length from the resource's allocator. The
754 * free algorithm will verify the free request parameters
755 * match an allocated range for the resource and that the
756 * range is owned by the instance requesting the free. If
757 * the free is validated the algorithm will free the
758 * resource then combine any resource nodes that may have
759 * become equivalent (in terms of ownership) after the
760 * allocation.
761 */
762 static int32_t treeFree(Rm_Allocator *allocator, Rm_AllocatorOpInfo *opInfo)
763 {
764 Rm_ResourceNode findNode;
765 Rm_ResourceNode *matchingNode = NULL;
766 Rm_ResourceNode *leftNode = NULL;
767 Rm_ResourceNode *rightNode = NULL;
768 bool combineLeft = false;
769 bool combineRight = false;
770 uint32_t findEnd;
771 uint32_t matchingEnd;
772 int32_t retVal;
774 memset((void *)&findNode, 0, sizeof(Rm_ResourceNode));
775 findNode.base = opInfo->resourceInfo->base;
776 findNode.length = opInfo->resourceInfo->length;
777 matchingNode = RB_FIND(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, &findNode);
779 if (matchingNode) {
780 findEnd = findNode.base + findNode.length - 1;
781 matchingEnd = matchingNode->base + matchingNode->length - 1;
783 if ((findNode.base >= matchingNode->base) && (findEnd <= matchingEnd)) {
784 if (matchingNode->allocationCount) {
785 if (isOwnedBy(matchingNode, opInfo->serviceSrcInstNode)) {
786 if ((findNode.base == matchingNode->base) && (findEnd == matchingEnd))
787 {
788 /* Case 1: Free range equals allocated matched node exactly. Attempt to combine
789 * freed node with nodes to left and right.
790 *
791 * |<--left node-->||<---matched node--->||<--right node-->|
792 * |<---free request--->|
793 */
794 leftNode = RB_PREV(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
795 rightNode = RB_NEXT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
796 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
797 deleteOwner(matchingNode, opInfo->serviceSrcInstNode);
799 if (leftNode && compareResourceNodeOwners(leftNode, matchingNode)) {
800 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
801 combineLeft = true;
802 }
803 if (rightNode && compareResourceNodeOwners(rightNode, matchingNode)) {
804 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
805 combineRight = true;
806 }
808 if (combineLeft && combineRight) {
809 /* Combine all three nodes into matchingNode */
810 matchingNode->base = leftNode->base;
811 matchingNode->length = leftNode->length + matchingNode->length + rightNode->length;
813 clearOwners(leftNode);
814 rmResourceNodeFree(leftNode);
815 clearOwners(rightNode);
816 rmResourceNodeFree(rightNode);
817 }
818 else if (combineLeft) {
819 /* Combine left and matching nodes. Reinsert right. */
820 matchingNode->base = leftNode->base;
821 matchingNode->length += leftNode->length;
823 clearOwners(leftNode);
824 rmResourceNodeFree(leftNode);
825 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
826 }
827 else if (combineRight) {
828 /* Combine right and matching nodes. Reinsert left. */
829 matchingNode->length += rightNode->length;
831 clearOwners(rightNode);
832 rmResourceNodeFree(rightNode);
833 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
834 }
835 else {
836 /* No combine. */
837 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
838 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
839 }
841 /* Always reinsert matchingNode */
842 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
843 }
844 else if ((findNode.base > matchingNode->base) && (findEnd < matchingEnd)) {
845 /* Case 2: Free range is less than range in matched node. Split
846 * matched node into three nodes.
847 *
848 * |<----------matched node---------->|
849 * |<---free request--->|
850 *
851 * Remove instance from AllocatedTo list then add it back in for side nodes for
852 * proper accounting of allocations in validInstance list
853 */
854 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
855 deleteOwner(matchingNode, opInfo->serviceSrcInstNode);
857 leftNode = rmResourceNodeNew(matchingNode->base, findNode.base - matchingNode->base);
858 copyOwners(leftNode, matchingNode);
859 addOwner(leftNode, opInfo->serviceSrcInstNode);
860 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
862 rightNode = rmResourceNodeNew(findNode.base + findNode.length, matchingEnd - findEnd);
863 copyOwners(rightNode, matchingNode);
864 addOwner(rightNode, opInfo->serviceSrcInstNode);
865 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
867 matchingNode->base = findNode.base;
868 matchingNode->length = findNode.length;
869 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
870 }
871 else {
872 if (findNode.base == matchingNode->base) {
873 /* Case 3: Free range is on left boundary of matched node. Try to
874 * combine free range with left node.
875 *
876 * |<---left node (free)--->||<----------matched node---------->|
877 * |<---findNode (free req)--->|
878 */
880 leftNode = RB_PREV(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
881 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
882 /* Remove freeing instance from owner list for compare with leftNode */
883 deleteOwner(matchingNode, opInfo->serviceSrcInstNode);
885 if (leftNode && compareResourceNodeOwners(leftNode, matchingNode)) {
886 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
887 /* Combine leftNode and findNode */
888 leftNode->length += findNode.length;
889 }
890 else {
891 leftNode = rmResourceNodeNew(findNode.base, findNode.length);
892 copyOwners(leftNode, matchingNode);
893 }
895 /* Remove leftNode range from matchingNode */
896 matchingNode->base = findNode.base + findNode.length;
897 matchingNode->length = matchingEnd - findEnd;
898 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
899 }
900 else if (findEnd == matchingEnd) {
901 /* Case 4: Free range is on right boundary of matched node. Try to
902 * combine free range with right node.
903 *
904 * |<----------matched node---------->||<---right node (free)--->|
905 * |<---findNode (free req)--->|
906 */
908 rightNode = RB_NEXT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
909 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
910 /* Remove freeing instance from owner list for compare with rightNode */
911 deleteOwner(matchingNode, opInfo->serviceSrcInstNode);
913 if (rightNode && compareResourceNodeOwners(rightNode, matchingNode)) {
914 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
915 /* Combine rightNode and findNode */
916 rightNode->base = findNode.base;
917 rightNode->length += findNode.length;
918 }
919 else {
920 rightNode = rmResourceNodeNew(findNode.base, findNode.length);
921 copyOwners(rightNode, matchingNode);
922 }
924 /* Remove rightNode range from matchingNode */
925 matchingNode->length -= findNode.length;
926 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
927 }
929 /* Add freeing instance back into matchingNode allocations */
930 addOwner(matchingNode, opInfo->serviceSrcInstNode);
931 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
932 }
934 retVal = RM_SERVICE_APPROVED;
935 }
936 else {
937 retVal = RM_SERVICE_DENIED_RES_NOT_ALLOCD_TO_INST;
938 }
939 }
940 else {
941 retVal = RM_SERVICE_DENIED_RES_ALREADY_FREE;
942 }
943 }
944 else {
945 retVal = RM_SERVICE_DENIED_PARTIAL_FREE;
946 }
947 }
948 else {
949 retVal = RM_SERVICE_DENIED_RES_RANGE_DOES_NOT_EXIST;
950 }
951 return(retVal);
952 }
954 /* FUNCTION PURPOSE: Issues a service response to application
955 ***********************************************************************
956 * DESCRIPTION: Provides a service response back to the application
957 * using the service callback function provided to
958 * the RM instance at the time of the service request.
959 */
960 static void serviceResponder (Rm_Inst *rmInst, Rm_Transaction *transaction)
961 {
962 Rm_ServiceRespInfo serviceResponse;
964 /* The responseTransaction will contain the resultant state details of
965 * the requestTransaction's service request */
966 serviceResponse.serviceState = transaction->state;
967 /* Pass back the ID that was provided to the component when it requested
968 * the service */
969 serviceResponse.serviceId = transaction->localId;
971 /* Service was approved and service was an allocate request. The resource
972 * data is passed back to the component */
973 if ((serviceResponse.serviceState == RM_SERVICE_APPROVED) &&
974 ((transaction->type == Rm_service_RESOURCE_ALLOCATE_INIT) ||
975 (transaction->type == Rm_service_RESOURCE_ALLOCATE_USE) ||
976 (transaction->type == Rm_service_RESOURCE_GET_BY_NAME)))
977 {
978 strncpy(serviceResponse.resourceName, transaction->resourceInfo.name, RM_NAME_MAX_CHARS);
979 serviceResponse.resourceBase = transaction->resourceInfo.base;
980 serviceResponse.resourceLength = transaction->resourceInfo.length;
981 }
983 /* Issue the callback to the requesting component with the response information */
984 transaction->callback.serviceCallback(&serviceResponse);
986 /* Delete the transaction from the transaction queue */
987 rmTransactionQueueDelete(rmInst, transaction->localId);
988 return;
989 }
991 /* FUNCTION PURPOSE: Sends RM response packets
992 ***********************************************************************
993 * DESCRIPTION: Sends RM response packets to RM instance's that sent
994 * RM request packets to the RM instance. The response
995 * is sent via the RM transport API which is plugged
996 * with an application created transport path.
997 */
998 static void transactionResponder (Rm_Inst *rmInst, Rm_Transaction *transaction)
999 {
1000 Rm_Transport *dstTransport = NULL;
1001 Rm_PacketHandle pktHandle = NULL;
1003 dstTransport = rmTransportFindRemoteName((Rm_Transport *) rmInst->transports, transaction->pktSrcInstName);
1005 switch (transaction->type) {
1006 case Rm_service_RESOURCE_ALLOCATE_INIT:
1007 case Rm_service_RESOURCE_ALLOCATE_USE:
1008 case Rm_service_RESOURCE_FREE:
1009 case Rm_service_RESOURCE_GET_BY_NAME:
1010 pktHandle = rmTransportCreateResourceResponsePkt(rmInst, dstTransport->appTransportHandle,
1011 transaction);
1012 break;
1013 case Rm_service_RESOURCE_MAP_TO_NAME:
1014 case Rm_service_RESOURCE_UNMAP_NAME:
1015 pktHandle = rmTransportCreateNsResponsePkt(rmInst, dstTransport->appTransportHandle,
1016 transaction);
1017 break;
1018 }
1020 if (pktHandle) {
1021 if (rmInst->transportCallouts.rmSendPkt) {
1022 if (rmInst->transportCallouts.rmSendPkt(dstTransport->appTransportHandle, pktHandle) < RM_OK) {
1023 transaction->state = RM_ERROR_TRANSPORT_SEND_ERROR;
1024 }
1025 }
1026 else {
1027 transaction->state = RM_ERROR_TRANSPORT_SEND_NOT_REGD;
1028 }
1029 }
1030 rmTransactionQueueDelete(rmInst, transaction->localId);
1031 }
1033 /* FUNCTION PURPOSE: Sends RM request packets
1034 ***********************************************************************
1035 * DESCRIPTION: Sends RM request packets to RM instance's that are
1036 * capable of forwarding or validating service requests.
1037 * The request is sent via the RM transport API which is
1038 * plugged with an application created transport path.
1039 */
1040 static void transactionForwarder (Rm_Inst *rmInst, Rm_Transaction *transaction)
1041 {
1042 Rm_Transport *dstTransport = NULL;
1043 Rm_PacketHandle pktHandle = NULL;
1045 if (rmInst->registeredWithDelegateOrServer) {
1046 if (rmInst->instType == Rm_instType_CLIENT) {
1047 dstTransport = rmTransportFindRemoteInstType((Rm_Transport *) rmInst->transports, Rm_instType_CLIENT_DELEGATE);
1049 if (!dstTransport) {
1050 dstTransport = rmTransportFindRemoteInstType((Rm_Transport *) rmInst->transports, Rm_instType_SERVER);
1051 }
1052 }
1053 else if (rmInst->instType == Rm_instType_CLIENT_DELEGATE) {
1054 dstTransport = rmTransportFindRemoteInstType((Rm_Transport *) rmInst->transports, Rm_instType_SERVER);
1055 }
1057 switch (transaction->type) {
1058 case Rm_service_RESOURCE_ALLOCATE_INIT:
1059 case Rm_service_RESOURCE_ALLOCATE_USE:
1060 case Rm_service_RESOURCE_FREE:
1061 case Rm_service_RESOURCE_GET_BY_NAME:
1062 pktHandle = rmTransportCreateResourceReqPkt(rmInst, dstTransport->appTransportHandle, transaction);
1063 break;
1064 case Rm_service_RESOURCE_MAP_TO_NAME:
1065 case Rm_service_RESOURCE_UNMAP_NAME:
1066 pktHandle = rmTransportCreateNsRequestPkt(rmInst, dstTransport->appTransportHandle, transaction);
1067 break;
1068 }
1070 if (pktHandle) {
1071 if (rmInst->transportCallouts.rmSendPkt) {
1072 if (rmInst->transportCallouts.rmSendPkt(dstTransport->appTransportHandle, pktHandle) < RM_OK) {
1073 transaction->state = RM_ERROR_TRANSPORT_SEND_ERROR;
1074 }
1075 }
1076 else {
1077 transaction->state = RM_ERROR_TRANSPORT_SEND_NOT_REGD;
1078 }
1079 }
1081 transaction->hasBeenForwarded = true;
1082 /* Transaction not deleted. Waiting for response from RM CD or Server */
1083 }
1084 }
1086 /* FUNCTION PURPOSE: Issues an allocator operation
1087 ***********************************************************************
1088 * DESCRIPTION: Issues an allocator preallocate, allocate, or free
1089 * for an RM resource.
1090 */
1091 static int32_t allocatorOperation(Rm_Inst *rmInst, Rm_AllocatorOpInfo *opInfo)
1092 {
1093 Rm_Allocator *allocator = NULL;
1094 int32_t resourceOffsetInPolicy;
1095 int32_t retVal;
1097 resourceOffsetInPolicy = rmPolicyGetResourceOffset(rmInst->policy, opInfo->resourceInfo->name);
1098 allocator = rmAllocatorFind(rmInst->allocators, opInfo->resourceInfo->name);
1100 if ((resourceOffsetInPolicy > 0) && allocator) {
1101 if (opInfo->operation == Rm_allocatorOp_PRE_ALLOCATE) {
1102 retVal = treePreAllocate(rmInst, allocator, resourceOffsetInPolicy, opInfo);
1103 }
1104 else if (opInfo->operation == Rm_allocatorOp_ALLOCATE) {
1105 retVal = treeAllocate(rmInst, allocator, resourceOffsetInPolicy, opInfo);
1106 }
1107 else if (opInfo->operation == Rm_allocatorOp_FREE) {
1108 retVal = treeFree(allocator, opInfo);
1109 }
1110 }
1111 else {
1112 /* Resource could not be found in policy and/or allocator */
1113 retVal = RM_SERVICE_DENIED_RES_DOES_NOT_EXIST;
1114 }
1115 return(retVal);
1116 }
1118 /* FUNCTION PURPOSE: Arbitrates allocation service requests
1119 ***********************************************************************
1120 * DESCRIPTION: Issues a set of allocator operations in order to
1121 * handle a received allocation request. Allocation
1122 * requests are always forwarded to the Server on Client
1123 * CD instances. If a request is made with a NameServer
1124 * name the resource base and length parameters are
1125 * retrieved from the NameServer prior to the allocation
1126 * attempt.
1127 */
1128 static void allocationHandler (Rm_Inst *rmInst, Rm_Transaction *transaction, void *validInstNode,
1129 uint32_t allocType)
1130 {
1131 Rm_AllocatorOpInfo opInfo;
1132 Rm_NameServerObjCfg nameServerObjCfg;
1133 int32_t retVal = transaction->state;
1135 memset((void *)&opInfo, 0, sizeof(Rm_AllocatorOpInfo));
1137 if (rmInst->instType == Rm_instType_CLIENT_DELEGATE) {
1138 /* Forward all allocation requests to Server if transport is up. Otherwise, just queue. */
1139 if (rmInst->registeredWithDelegateOrServer) {
1140 transactionForwarder(rmInst, transaction);
1141 }
1142 }
1143 else if (rmInst->instType == Rm_instType_SERVER) {
1144 opInfo.resourceInfo = &transaction->resourceInfo;
1145 opInfo.serviceSrcInstNode = validInstNode;
1146 opInfo.allocType = allocType;
1148 /* Populated NameServer name has precedence over base */
1149 if (strlen(transaction->resourceInfo.nameServerName) > 0) {
1150 if ((transaction->resourceInfo.base == 0) &&
1151 (transaction->resourceInfo.length == 0) &&
1152 (transaction->resourceInfo.alignment == 0)) {
1153 memset((void *)&nameServerObjCfg, 0, sizeof(Rm_NameServerObjCfg));
1154 nameServerObjCfg.nameServerTree = rmInst->nameServer;
1155 nameServerObjCfg.nodeCfg.objName = transaction->resourceInfo.nameServerName;
1156 if ((retVal = rmNameServerFindObject(&nameServerObjCfg)) == RM_SERVICE_PROCESSING) {
1157 strncpy(transaction->resourceInfo.name, nameServerObjCfg.nodeCfg.resourceName, RM_NAME_MAX_CHARS);
1158 transaction->resourceInfo.base = nameServerObjCfg.nodeCfg.resourceBase;
1159 transaction->resourceInfo.length = nameServerObjCfg.nodeCfg.resourceLength;
1160 }
1161 }
1162 else {
1163 retVal = RM_ERROR_NS_NAME_AND_RES_VAL_CONFLICT;
1164 }
1165 }
1167 if (retVal == RM_SERVICE_PROCESSING) {
1168 if (transaction->resourceInfo.base == RM_RESOURCE_BASE_UNSPECIFIED) {
1169 opInfo.operation = Rm_allocatorOp_PRE_ALLOCATE;
1170 retVal = allocatorOperation(rmInst, &opInfo);
1171 }
1173 if (retVal == RM_SERVICE_PROCESSING) {
1174 opInfo.operation = Rm_allocatorOp_ALLOCATE;
1175 retVal = allocatorOperation(rmInst, &opInfo);
1176 }
1177 }
1179 transaction->state = retVal;
1181 if (strncmp(transaction->serviceSrcInstName, rmInst->instName, RM_NAME_MAX_CHARS)) {
1182 /* Source of allocation was not the server instance, provide the transaction
1183 * to the transaction responder */
1184 transactionResponder(rmInst, transaction);
1185 }
1186 /* Otherwise let the return stack return the transaction to the serviceHandler */
1187 }
1188 }
1190 /* FUNCTION PURPOSE: Arbitrates free service requests
1191 ***********************************************************************
1192 * DESCRIPTION: Issues a set of allocator operations in order to
1193 * handle a received free request. Free
1194 * requests are always forwarded to the Server on Client
1195 * CD instances. If a request is made with a NameServer
1196 * name the resource base and length parameters are
1197 * retrieved from the NameServer prior to the free
1198 * attempt.
1199 */
1200 static void freeHandler (Rm_Inst *rmInst, Rm_Transaction *transaction, void *validInstNode)
1201 {
1202 Rm_AllocatorOpInfo opInfo;
1203 Rm_NameServerObjCfg nameServerObjCfg;
1204 int32_t retVal = transaction->state;
1206 memset((void *)&opInfo, 0, sizeof(Rm_AllocatorOpInfo));
1208 if (rmInst->instType == Rm_instType_CLIENT_DELEGATE) {
1209 /* Forward all free requests to Server if transport is up. Otherwise, just queue. */
1210 if (rmInst->registeredWithDelegateOrServer) {
1211 transactionForwarder(rmInst, transaction);
1212 }
1213 }
1214 else if (rmInst->instType == Rm_instType_SERVER) {
1215 opInfo.resourceInfo = &transaction->resourceInfo;
1216 opInfo.serviceSrcInstNode = validInstNode;
1218 /* Populated NameServer name has precedence over base */
1219 if (strlen(transaction->resourceInfo.nameServerName) > 0) {
1220 if ((transaction->resourceInfo.base == 0) &&
1221 (transaction->resourceInfo.length == 0) &&
1222 (transaction->resourceInfo.alignment == 0)) {
1223 memset((void *)&nameServerObjCfg, 0, sizeof(Rm_NameServerObjCfg));
1224 nameServerObjCfg.nameServerTree = rmInst->nameServer;
1225 nameServerObjCfg.nodeCfg.objName = transaction->resourceInfo.nameServerName;
1226 if ((retVal = rmNameServerFindObject(&nameServerObjCfg)) == RM_SERVICE_PROCESSING) {
1227 strncpy(transaction->resourceInfo.name, nameServerObjCfg.nodeCfg.resourceName, RM_NAME_MAX_CHARS);
1228 transaction->resourceInfo.base = nameServerObjCfg.nodeCfg.resourceBase;
1229 transaction->resourceInfo.length = nameServerObjCfg.nodeCfg.resourceLength;
1230 }
1231 }
1232 else {
1233 retVal = RM_ERROR_NS_NAME_AND_RES_VAL_CONFLICT;
1234 }
1235 }
1237 if(retVal == RM_SERVICE_PROCESSING) {
1238 opInfo.operation = Rm_allocatorOp_FREE;
1239 retVal = allocatorOperation(rmInst, &opInfo);
1240 }
1242 transaction->state = retVal;
1244 if (strncmp(transaction->serviceSrcInstName, rmInst->instName, RM_NAME_MAX_CHARS)) {
1245 /* Source of allocation was not the server instance, provide the transaction
1246 * to the transaction responder */
1247 transactionResponder(rmInst, transaction);
1248 }
1249 /* Otherwise let the return stack return the transaction to the serviceHandler */
1250 }
1251 }
1253 /* FUNCTION PURPOSE: Reserves a Linux resource
1254 ***********************************************************************
1255 * DESCRIPTION: Reserves resources for Linux using the base and length
1256 * values retrieved from the Linux DTB via the
1257 * "linux-dtb-alias" properties within the GRL.
1258 */
1259 static int32_t reserveLinuxResource(Rm_Inst *rmInst, Rm_LinuxAlias *linuxAlias,
1260 Rm_LinuxValueRange *linuxValues, Rm_AllocatorOpInfo *opInfo)
1261 {
1262 int32_t retVal = RM_OK;
1263 bool baseFound = false;
1264 bool lengthFound = false;
1265 uint32_t valueIndex = 0;
1267 while ((linuxValues) && (!baseFound || !lengthFound)) {
1268 if (linuxAlias->baseOffset == valueIndex) {
1269 opInfo->resourceInfo->base = linuxValues->value;
1270 baseFound = true;
1272 if (linuxAlias->lengthOffset == RM_DTB_UTIL_LINUX_ALIAS_OFFSET_NOT_SET) {
1273 opInfo->resourceInfo->length = 1;
1274 lengthFound = true;
1275 }
1276 }
1277 else if (linuxAlias->lengthOffset == valueIndex) {
1278 opInfo->resourceInfo->length = linuxValues->value;
1279 lengthFound = true;
1280 }
1282 linuxValues = (Rm_LinuxValueRange *)linuxValues->nextValue;
1283 valueIndex++;
1284 }
1286 if (!baseFound || !lengthFound) {
1287 retVal = RM_ERROR_DATA_NOT_FOUND_AT_LINUX_ALIAS;
1288 }
1289 else {
1290 /* Allocate resource to Linux */
1291 retVal = allocatorOperation(rmInst, opInfo);
1292 }
1293 return (retVal);
1294 }
1296 /* FUNCTION PURPOSE: Finds and reserves Linux resources
1297 ***********************************************************************
1298 * DESCRIPTION: Parses the Linux DTB for resources consumed by the
1299 * Linux kernel. If the resource is found via the
1300 * "linux-dtb-alias" property defined in the GRL it is
1301 * reserved.
1302 */
1303 static int32_t findAndReserveLinuxResource(Rm_Inst *rmInst, const char *resourceName, void *linuxDtb,
1304 Rm_LinuxAlias *linuxAlias)
1305 {
1306 Rm_AllocatorOpInfo opInfo;
1307 Rm_ResourceInfo resourceInfo;
1308 uint32_t pathOffset;
1309 uint32_t pathSize;
1310 char *spacePtr;
1311 int32_t propOffset;
1312 int32_t nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;
1313 int32_t prevDepth = RM_DTB_UTIL_STARTING_DEPTH;
1314 int32_t depth;
1315 int32_t propertyLen;
1316 const char *propertyName;
1317 const void *propertyData;
1318 Rm_LinuxValueRange *linuxValueRange;
1319 int32_t retVal = RM_OK;
1321 memset((void *) &opInfo, 0, sizeof(Rm_AllocatorOpInfo));
1322 memset((void *) &resourceInfo, 0, sizeof(Rm_ResourceInfo));
1324 strncpy(resourceInfo.name, resourceName, RM_NAME_MAX_CHARS);
1325 opInfo.serviceSrcInstNode = rmPolicyGetLinuxInstNode(rmInst->validInstances);
1326 opInfo.operation = Rm_allocatorOp_ALLOCATE;
1327 opInfo.resourceInfo = &resourceInfo;
1329 while(linuxAlias) {
1330 /* Reset parsing variables */
1331 pathOffset = 0;
1332 pathSize = strlen(linuxAlias->path) + 1;
1333 nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;
1334 prevDepth = RM_DTB_UTIL_STARTING_DEPTH;
1335 resourceInfo.base = 0;
1336 resourceInfo.length = 0;
1338 spacePtr = strpbrk(linuxAlias->path, " ");
1339 if (spacePtr) {
1340 *spacePtr = '\0';
1341 }
1343 while(pathOffset < pathSize) {
1344 /* Move through DTB nodes until next alias path node found */
1345 if (strcmp(linuxAlias->path + pathOffset, fdt_get_name(linuxDtb, nodeOffset, NULL))) {
1346 nodeOffset = fdt_next_node(linuxDtb, nodeOffset, &depth);
1348 if ((depth < prevDepth) || (nodeOffset == -FDT_ERR_NOTFOUND)) {
1349 /* Returning from subnode that matched part of alias path without finding
1350 * resource values */
1351 retVal = RM_ERROR_DATA_NOT_FOUND_AT_LINUX_ALIAS;
1352 break;
1353 }
1354 }
1355 else {
1356 /* Found next alias path node. Move to next node name in path string. */
1357 pathOffset += (strlen(linuxAlias->path + pathOffset) + 1);
1358 spacePtr = strpbrk(linuxAlias->path + pathOffset, " ");
1359 if (spacePtr) {
1360 *spacePtr = '\0';
1361 }
1363 prevDepth = fdt_node_depth(linuxDtb, nodeOffset);
1364 propOffset = fdt_first_property_offset(linuxDtb, nodeOffset);
1365 while ((propOffset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) &&
1366 (pathOffset < pathSize)) {
1367 propertyData = fdt_getprop_by_offset(linuxDtb, propOffset,
1368 &propertyName, &propertyLen);
1370 if (strcmp(linuxAlias->path + pathOffset, propertyName) == 0) {
1371 /* Found resource at end of alias path */
1372 pathOffset += (strlen(linuxAlias->path + pathOffset) + 1);
1373 linuxValueRange = rmDtbUtilLinuxExtractValues(propertyData, propertyLen);
1374 retVal = reserveLinuxResource(rmInst, linuxAlias,
1375 linuxValueRange, &opInfo);
1376 rmDtbUtilLinuxFreeValues(linuxValueRange);
1377 }
1378 propOffset = fdt_next_property_offset(linuxDtb, propOffset);
1379 }
1381 if (propOffset < -FDT_ERR_NOTFOUND) {
1382 retVal = propOffset;
1383 break;
1384 }
1385 }
1386 }
1388 if (retVal < RM_OK) {
1389 break;
1390 }
1391 linuxAlias = linuxAlias->nextLinuxAlias;
1392 }
1393 return (retVal);
1394 }
1396 /* FUNCTION PURPOSE: Creates and initializes a resource allocator
1397 ***********************************************************************
1398 * DESCRIPTION: Creates a resource allocator for the provided
1399 * resource name and resource properties retrieved
1400 * from the GRL. Resources will be reserved for
1401 * the Linux kernel if the Linux DTB is provided
1402 * and there are "linux-dtb-alias" properties
1403 * specified in the GRL.
1404 */
1405 static int32_t createAndInitAllocator(Rm_Inst *rmInst, const char *resourceName,
1406 Rm_ResourceProperties *resourceProperties, void *linuxDtb)
1407 {
1408 Rm_ResourceRange *range = NULL;
1409 Rm_ResourceRange *rangeBasePtr = NULL;
1410 Rm_NsAssignment *nsAssignments = NULL;
1411 Rm_NsAssignment *nsAssignmentBasePtr = NULL;
1412 Rm_LinuxAlias *linuxAlias = NULL;
1413 Rm_NameServerObjCfg nameServerObjCfg;
1414 int32_t retVal = RM_OK;
1416 if (resourceProperties->rangeData && (resourceProperties->rangeLen > 0)) {
1417 range = rangeBasePtr = rmDtbUtilResExtractRange(resourceProperties->rangeData,
1418 resourceProperties->rangeLen);
1420 if ((retVal = createResourceTree(rmInst, resourceName, range)) >= RM_OK) {
1421 if (resourceProperties->linuxAliasData && resourceProperties->linuxAliasLen) {
1422 if (linuxDtb) {
1423 linuxAlias = rmDtbUtilResExtractLinuxAlias(resourceProperties->linuxAliasData,
1424 resourceProperties->linuxAliasLen, &retVal);
1425 if (linuxAlias) {
1426 retVal = findAndReserveLinuxResource(rmInst, resourceName, linuxDtb, linuxAlias);
1427 }
1428 }
1429 else {
1430 retVal = RM_ERROR_GRL_LINUX_ALIAS_BUT_NO_DTB;
1431 }
1432 }
1433 }
1434 }
1436 if (retVal >= RM_OK) {
1437 if (resourceProperties->nsAssignData && resourceProperties->nsAssignLen) {
1438 nsAssignments = rmDtbUtilResExtractNsAssignment(resourceProperties->nsAssignData,
1439 resourceProperties->nsAssignLen, &retVal);
1440 if (nsAssignments) {
1441 nsAssignmentBasePtr = nsAssignments;
1442 while (nsAssignments) {
1443 memset((void *)&nameServerObjCfg, 0, sizeof(Rm_NameServerObjCfg));
1444 nameServerObjCfg.nameServerTree = rmInst->nameServer;
1445 nameServerObjCfg.nodeCfg.objName = nsAssignments->nsName;
1446 nameServerObjCfg.nodeCfg.resourceName = (char *)resourceName;
1447 nameServerObjCfg.nodeCfg.resourceBase= nsAssignments->resourceBase;
1448 nameServerObjCfg.nodeCfg.resourceLength = nsAssignments->resourceLength;
1449 rmNameServerAddObject(&nameServerObjCfg);
1450 nsAssignments = nsAssignments->nextNsAssignment;
1451 }
1452 rmDtbUtilResFreeNsAssignmentList(nsAssignmentBasePtr);
1453 }
1454 }
1455 }
1457 rmDtbUtilResFreeRange(rangeBasePtr);
1458 if (linuxAlias) {
1459 rmDtbUtilResFreeLinuxAlias(linuxAlias);
1460 }
1461 return(retVal);
1462 }
1464 /* FUNCTION PURPOSE: Recursively parses GRL resource properties
1465 ***********************************************************************
1466 * DESCRIPTION: Recursively parses and stores GRL resource node
1467 * properties using the LIBFDT APIs
1468 */
1469 static int32_t parseResourceProperty(void *globalResourceDtb, int32_t offset,
1470 Rm_ResourceProperties *propertyInfo)
1471 {
1472 int32_t propertyLen;
1473 const char *propertyName;
1474 const void *propertyData;
1475 Rm_ResourcePropType propertyType;
1476 int32_t retVal = RM_OK;
1478 propertyData = fdt_getprop_by_offset(globalResourceDtb, offset, &propertyName, &propertyLen);
1479 propertyType = rmDtbUtilResGetPropertyType(propertyName);
1480 if (propertyType == Rm_resourcePropType_RESOURCE_RANGE) {
1481 propertyInfo->rangeData = propertyData;
1482 propertyInfo->rangeLen = propertyLen;
1483 }
1484 else if (propertyType == Rm_resourcePropType_NSASSIGNMENT) {
1485 propertyInfo->nsAssignData = propertyData;
1486 propertyInfo->nsAssignLen = propertyLen;
1487 }
1488 else if (propertyType == Rm_resourcePropType_RESOURCE_LINUX_ALIAS) {
1489 propertyInfo->linuxAliasData = propertyData;
1490 propertyInfo->linuxAliasLen = propertyLen;
1491 }
1492 else {
1493 retVal = RM_ERROR_GRL_UNKNOWN_RESOURCE_PROPERTY;
1494 }
1496 if (retVal == RM_OK) {
1497 offset = fdt_next_property_offset(globalResourceDtb, offset);
1498 if (offset >= 0) {
1499 retVal = parseResourceProperty(globalResourceDtb, offset, propertyInfo);
1500 }
1501 else if (offset != -FDT_ERR_NOTFOUND) {
1502 /* Error returned by LIBFDT */
1503 retVal = offset;
1504 }
1505 }
1506 return (retVal);
1507 }
1509 /* FUNCTION PURPOSE: Recursively parses GRL resource nodes
1510 ***********************************************************************
1511 * DESCRIPTION: Recursively parses GRL resource nodes looking for
1512 * resource properties to create the resource allocators.
1513 * The LIBFDT APIs are used to parse the GRL.
1514 */
1515 static int32_t parseResourceNode(Rm_Inst *rmInst, void *globalResourceDtb, int32_t nodeOffset, int32_t depth,
1516 void *linuxDtb)
1517 {
1518 const char *resourceName = fdt_get_name(globalResourceDtb, nodeOffset, NULL);
1519 Rm_ResourceProperties resourceProperties;
1520 int32_t retVal = RM_OK;
1521 int32_t offset;
1523 memset((void *)&resourceProperties, 0, sizeof(Rm_ResourceProperties));
1524 /* Get properties of resource node */
1525 offset = fdt_first_property_offset(globalResourceDtb, nodeOffset);
1526 if (offset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) {
1527 retVal = parseResourceProperty(globalResourceDtb, offset, &resourceProperties);
1528 if (retVal < -FDT_ERR_NOTFOUND) {
1529 return (retVal);
1530 }
1531 if (retVal = createAndInitAllocator(rmInst, resourceName, &resourceProperties, linuxDtb) < RM_OK) {
1532 return (retVal);
1533 }
1534 }
1535 else if (offset != -FDT_ERR_NOTFOUND) {
1536 /* Error returned by LIBFDT */
1537 return (offset);
1538 }
1540 offset = fdt_next_node(globalResourceDtb, nodeOffset, &depth);
1541 if ((offset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) && (depth >= RM_DTB_UTIL_STARTING_DEPTH)) {
1542 retVal = parseResourceNode(rmInst, globalResourceDtb, offset, depth, linuxDtb);
1543 if (retVal < -FDT_ERR_NOTFOUND) {
1544 return (retVal);
1545 }
1546 }
1547 else if (offset != -FDT_ERR_NOTFOUND) {
1548 /* Error returned by LIBFDT */
1549 return (offset);
1550 }
1551 return (retVal);
1552 }
1554 /* FUNCTION PURPOSE: Initializes server allocators
1555 ***********************************************************************
1556 * DESCRIPTION: Creates and initializes a server instance's
1557 * resource allocators using the GRL and, if
1558 * provided, Linux DTB.
1559 */
1560 static int32_t initializeAllocators(Rm_Inst *rmInst, void *globalResourceDtb, void *linuxDtb)
1561 {
1562 int32_t nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;
1563 int32_t startDepth = RM_DTB_UTIL_STARTING_DEPTH;
1564 int32_t result = RM_OK;
1566 /* Recursively parse the Global Resource List, creating an allocator for
1567 * each resource as specified in the node */
1568 result = parseResourceNode(rmInst, globalResourceDtb, nodeOffset, startDepth, linuxDtb);
1570 return(result);
1571 }
1573 /**********************************************************************
1574 ********************** Internal Functions ****************************
1575 **********************************************************************/
1577 /* FUNCTION PURPOSE: Adds a transaction
1578 ***********************************************************************
1579 * DESCRIPTION: Returns a pointer to a newly created transaction.
1580 * The transaction is created based on a new service
1581 * request received via the service API or the
1582 * transport API (service forwarded from another instance)
1583 */
1584 Rm_Transaction *rmTransactionQueueAdd(Rm_Inst *rmInst)
1585 {
1586 Rm_Transaction *transactionQueue = rmInst->transactionQueue;
1587 Rm_Transaction *newTransaction = NULL;
1589 newTransaction = Rm_osalMalloc(sizeof(Rm_Transaction));
1590 if (newTransaction) {
1591 memset((void *)newTransaction, 0, sizeof(Rm_Transaction));
1593 newTransaction->localId = transactionGetSequenceNum(rmInst);
1594 newTransaction->nextTransaction = NULL;
1595 if (transactionQueue) {
1596 while (transactionQueue->nextTransaction) {
1597 transactionQueue = transactionQueue->nextTransaction;
1598 }
1599 transactionQueue->nextTransaction = newTransaction;
1600 }
1601 else {
1602 rmInst->transactionQueue = newTransaction;
1603 }
1604 }
1605 return (newTransaction);
1606 }
1608 /* FUNCTION PURPOSE: Finds a transaction
1609 ***********************************************************************
1610 * DESCRIPTION: Returns a pointer to a transaction resident
1611 * in the transaction queue that matches the provided
1612 * transaction ID.
1613 */
1614 Rm_Transaction *rmTransactionQueueFind(Rm_Inst *rmInst, uint32_t transactionId)
1615 {
1616 Rm_Transaction *transaction = rmInst->transactionQueue;
1618 while (transaction) {
1619 if (transaction->localId == transactionId) {
1620 break;
1621 }
1622 transaction = transaction->nextTransaction;
1623 }
1625 return (transaction);
1626 }
1628 /* FUNCTION PURPOSE: Deletes a transaction
1629 ***********************************************************************
1630 * DESCRIPTION: Deletes the transaction with the provided transaction
1631 * ID from the instance's transaction queue.
1632 */
1633 int32_t rmTransactionQueueDelete(Rm_Inst *rmInst, uint32_t transactionId)
1634 {
1635 Rm_Transaction *transaction = rmInst->transactionQueue;
1636 Rm_Transaction *prevTransaction = NULL;
1637 int32_t retVal = RM_OK;
1639 while (transaction) {
1640 if (transaction->localId == transactionId) {
1641 break;
1642 }
1644 prevTransaction = transaction;
1645 transaction = transaction->nextTransaction;
1646 }
1648 if (transaction) {
1649 if (prevTransaction == NULL) {
1650 /* Transaction at start of queue. Map second transaction to start of queue
1651 * as long as more than one transactions. */
1652 rmInst->transactionQueue = transaction->nextTransaction;
1653 }
1654 else {
1655 /* Transaction in middle or end of queue. */
1656 prevTransaction->nextTransaction = transaction->nextTransaction;
1657 }
1658 Rm_osalFree((void *)transaction, sizeof(Rm_Transaction));
1659 }
1660 else {
1661 retVal = RM_ERROR_SERVICE_TRANS_DOES_NOT_EXIST;
1662 }
1663 return (retVal);
1664 }
1666 /* FUNCTION PURPOSE: Finds an allocator
1667 ***********************************************************************
1668 * DESCRIPTION: Returns a pointer to an allocator that matches the
1669 * provided resource name.
1670 */
1671 Rm_Allocator *rmAllocatorFind(Rm_Allocator *allocatorList, char *resourceName)
1672 {
1673 while (allocatorList) {
1674 if (strncmp(allocatorList->resourceName, resourceName, RM_NAME_MAX_CHARS) == 0) {
1675 break;
1676 }
1677 allocatorList = allocatorList->nextAllocator;
1678 }
1680 return (allocatorList);
1681 }
1683 /* FUNCTION PURPOSE: Processes a transaction
1684 ***********************************************************************
1685 * DESCRIPTION: Processes transactions created from services
1686 * received via the service handle or the transport.
1687 * Transactions will be routed within the RM system
1688 * based on the RM instance type and the type of
1689 * the transaction.
1690 */
1691 void rmTransactionProcessor (Rm_Inst *rmInst, Rm_Transaction *transaction)
1692 {
1693 void *validInstNode;
1694 Rm_PolicyCheckCfg privCheckCfg;
1695 Rm_NameServerObjCfg nameServerObjCfg;
1696 uint32_t allocType = 0;
1698 /* Handle static transactions originating on this instance. Any other static transactions will be
1699 * stored in transaction queue until all transports are up. */
1700 if (((rmInst->instType == Rm_instType_CLIENT) || (rmInst->instType == Rm_instType_CLIENT_DELEGATE)) &&
1701 (!rmInst->registeredWithDelegateOrServer) &&
1702 (strncmp(transaction->serviceSrcInstName, rmInst->instName, RM_NAME_MAX_CHARS) == 0)) {
1703 if (rmInst->staticInfo.staticPolicy) {
1704 if ((transaction->type == Rm_service_RESOURCE_ALLOCATE_INIT) ||
1705 (transaction->type == Rm_service_RESOURCE_ALLOCATE_USE)) {
1706 /* Check request against startup policy */
1707 memset((void *)&privCheckCfg, 0, sizeof(Rm_PolicyCheckCfg));
1709 if (transaction->type == Rm_service_RESOURCE_ALLOCATE_INIT) {
1710 privCheckCfg.type = Rm_policyCheck_INIT;
1711 }
1712 else {
1713 privCheckCfg.type = Rm_policyCheck_USE;
1714 }
1715 privCheckCfg.policyDtb = rmInst->staticInfo.staticPolicy;
1716 privCheckCfg.validInstNode = rmPolicyGetValidInstNode(rmInst->staticInfo.staticValidInstTree,
1717 rmInst->instName);
1718 privCheckCfg.resourceOffset = rmPolicyGetResourceOffset(rmInst->staticInfo.staticPolicy,
1719 transaction->resourceInfo.name);
1720 privCheckCfg.resourceBase = transaction->resourceInfo.base;
1721 privCheckCfg.resourceLength = transaction->resourceInfo.length;
1723 if (rmPolicyCheckPrivilege(&privCheckCfg, &transaction->state)) {
1724 transaction->state = RM_SERVICE_APPROVED_STATIC;
1725 }
1726 else if (transaction->state == RM_SERVICE_PROCESSING) {
1727 /* Privilege check returned false without error */
1728 transaction->state = RM_SERVICE_DENIED_BY_STATIC_POLICY;
1729 }
1730 }
1731 else {
1732 transaction->state = RM_SERVICE_DENIED_INVALID_STATIC_REQUEST;
1733 }
1734 }
1735 else {
1736 transaction->state = RM_ERROR_REQ_FAILED_NO_STATIC_POLICY;
1737 }
1738 }
1739 else {
1740 /* Handle auto-forwarded transactions. These transactions include:
1741 * - All request transactions received on Clients are forwarded to the Client Delegate
1742 * - NameServer requests received on the Client Delegate are forwarded to the Server */
1743 if ((rmInst->instType == Rm_instType_CLIENT) ||
1744 ((rmInst->instType == Rm_instType_CLIENT_DELEGATE) &&
1745 ((transaction->type == Rm_service_RESOURCE_MAP_TO_NAME) ||
1746 (transaction->type == Rm_service_RESOURCE_GET_BY_NAME) ||
1747 (transaction->type == Rm_service_RESOURCE_UNMAP_NAME)))) {
1749 if ((transaction->state != RM_SERVICE_PROCESSING) &&
1750 (transaction->state != RM_SERVICE_APPROVED_STATIC)) {
1751 if (strncmp(transaction->serviceSrcInstName, rmInst->instName, RM_NAME_MAX_CHARS)) {
1752 /* Transaction did not originate on this instance */
1753 transactionResponder(rmInst, transaction);
1754 }
1755 else {
1756 /* Transaction originated on this instance */
1757 serviceResponder(rmInst, transaction);
1758 }
1759 }
1760 else {
1761 /* Forward request if transport is up. Otherwise, just queue. */
1762 if (rmInst->registeredWithDelegateOrServer) {
1763 transactionForwarder(rmInst, transaction);
1764 }
1765 }
1766 }
1767 else {
1768 /* Validate service's originating instance name */
1769 if (rmInst->instType == Rm_instType_SERVER) {
1770 validInstNode = rmPolicyGetValidInstNode(rmInst->validInstances, transaction->serviceSrcInstName);
1771 if (validInstNode == NULL) {
1772 transaction->state = RM_SERVICE_DENIED_INST_NAME_NOT_VALID;
1774 /* Send result via responder if transaction did not originate from this instance */
1775 if (strncmp(transaction->serviceSrcInstName, rmInst->instName, RM_NAME_MAX_CHARS)) {
1776 transactionResponder(rmInst, transaction);
1777 }
1778 }
1779 }
1781 switch (transaction->type) {
1782 case Rm_service_RESOURCE_ALLOCATE_INIT:
1783 case Rm_service_RESOURCE_ALLOCATE_USE:
1784 case Rm_service_RESOURCE_FREE:
1785 if ((transaction->state != RM_SERVICE_PROCESSING) &&
1786 (transaction->state != RM_SERVICE_APPROVED_STATIC)) {
1787 /* Transaction complete */
1788 if (strncmp(transaction->serviceSrcInstName, rmInst->instName, RM_NAME_MAX_CHARS)) {
1789 /* Transaction result not destined for this instance */
1790 transactionResponder(rmInst, transaction);
1791 }
1792 else {
1793 /* Transaction result destined for this instance */
1794 serviceResponder(rmInst, transaction);
1795 }
1796 }
1797 else {
1798 /* Complete allocation/free request */
1799 if (transaction->type == Rm_service_RESOURCE_FREE) {
1800 freeHandler(rmInst, transaction, validInstNode);
1801 }
1802 else {
1803 switch (transaction->type) {
1804 case Rm_service_RESOURCE_ALLOCATE_INIT:
1805 RM_policy_SET_PERM(allocType, RM_POLICY_PERM_INIT_SHIFT, 1);
1806 break;
1807 case Rm_service_RESOURCE_ALLOCATE_USE:
1808 RM_policy_SET_PERM(allocType, RM_POLICY_PERM_USE_SHIFT, 1);
1809 break;
1810 }
1811 allocationHandler(rmInst, transaction, validInstNode, allocType);
1812 }
1813 }
1814 break;
1815 case Rm_service_RESOURCE_MAP_TO_NAME:
1816 case Rm_service_RESOURCE_GET_BY_NAME:
1817 case Rm_service_RESOURCE_UNMAP_NAME:
1818 /* NameServer resides on server */
1819 memset((void *)&nameServerObjCfg, 0, sizeof(Rm_NameServerObjCfg));
1820 if (rmInst->nameServer) {
1821 nameServerObjCfg.nameServerTree = rmInst->nameServer;
1822 nameServerObjCfg.nodeCfg.objName = transaction->resourceInfo.nameServerName;
1823 if (transaction->type == Rm_service_RESOURCE_MAP_TO_NAME) {
1824 nameServerObjCfg.nodeCfg.resourceName = transaction->resourceInfo.name;
1825 nameServerObjCfg.nodeCfg.resourceBase= transaction->resourceInfo.base;
1826 nameServerObjCfg.nodeCfg.resourceLength = transaction->resourceInfo.length;
1827 transaction->state = rmNameServerAddObject(&nameServerObjCfg);
1828 }
1829 else if (transaction->type == Rm_service_RESOURCE_GET_BY_NAME) {
1830 if ((transaction->state = rmNameServerFindObject(&nameServerObjCfg)) ==
1831 RM_SERVICE_PROCESSING) {
1832 strncpy(transaction->resourceInfo.name, nameServerObjCfg.nodeCfg.resourceName, RM_NAME_MAX_CHARS);
1833 transaction->resourceInfo.base = nameServerObjCfg.nodeCfg.resourceBase;
1834 transaction->resourceInfo.length = nameServerObjCfg.nodeCfg.resourceLength;
1835 transaction->state = RM_SERVICE_APPROVED;
1836 }
1837 }
1838 else if (transaction->type == Rm_service_RESOURCE_UNMAP_NAME) {
1839 transaction->state = rmNameServerDeleteObject(&nameServerObjCfg);
1840 }
1841 }
1842 else {
1843 transaction->state = RM_ERROR_NAMESERVER_DOES_NOT_EXIST;
1844 }
1846 /* Send result via responder if transaction did not originate from this instance */
1847 if (strncmp(transaction->serviceSrcInstName, rmInst->instName, RM_NAME_MAX_CHARS)) {
1848 transactionResponder(rmInst, transaction);
1849 }
1850 break;
1851 }
1852 }
1853 }
1855 /* Forward any queued requests that weren't forwarded yet */
1856 if (rmInst->registeredWithDelegateOrServer) {
1857 transaction = rmInst->transactionQueue;
1858 while(transaction) {
1859 if (((transaction->state == RM_SERVICE_PROCESSING) ||
1860 (transaction->state == RM_SERVICE_APPROVED_STATIC)) &&
1861 !transaction->hasBeenForwarded) {
1862 transactionForwarder(rmInst, transaction);
1863 }
1864 transaction = transaction->nextTransaction;
1865 }
1866 }
1867 }
1869 /**********************************************************************
1870 ********************** Application visible APIs **********************
1871 **********************************************************************/
1873 /* FUNCTION PURPOSE: Display status of managed resources
1874 ***********************************************************************
1875 * DESCRIPTION: Prints the status (allocate/free status, as well as
1876 * owners) for all resources managed by the RM
1877 * instance network. Also, prints the NameServer name
1878 * entries. This function is only available on server
1879 * instances.
1880 */
1881 void Rm_printResourceStatus(Rm_Handle rmServerHandle)
1882 {
1883 Rm_Inst *rmInst = (Rm_Inst *)rmServerHandle;
1884 Rm_Allocator *allocator = rmInst->allocators;
1885 Rm_Owner *owners;
1886 Rm_ResourceTree *treeRoot;
1887 Rm_ResourceNode *treeNode;
1889 if (rmInst->instType == Rm_instType_SERVER) {
1890 while (allocator != NULL) {
1891 Rm_osalLog("Resource: %s\n", allocator->resourceName);
1893 treeRoot = allocator->allocatorRootEntry;
1895 RB_FOREACH(treeNode, _Rm_AllocatorResourceTree, treeRoot) {
1896 Rm_osalLog(" %10d - %10d ", treeNode->base,
1897 treeNode->base + treeNode->length -1);
1899 if (treeNode->allocationCount == 0) {
1900 Rm_osalLog("NOT ALLOCATED\n");
1901 }
1902 else {
1903 owners = treeNode->ownerList;
1904 Rm_osalLog("allocated to");
1905 while (owners) {
1906 Rm_osalLog(" %s", owners->instNameNode->name);
1907 owners = owners->nextOwner;
1908 }
1909 Rm_osalLog("\n");
1910 }
1911 }
1912 allocator = allocator->nextAllocator;
1913 }
1914 rmNameServerPrintObjects(rmInst->nameServer);
1915 }
1916 }
1918 /* FUNCTION PURPOSE: Display status of a RM instance
1919 ***********************************************************************
1920 * DESCRIPTION: Prints the current status of various RM instance
1921 * properties such as the state of all transactions
1922 * in the transaction queue and registered transports
1923 */
1924 void Rm_printInstanceStatus(Rm_Handle rmHandle)
1925 {
1926 Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
1927 Rm_Transport *transportList = (Rm_Transport *)rmInst->transports;
1928 Rm_Transaction *transactionQ = rmInst->transactionQueue;
1930 Rm_osalLog("Instance name: %s\n", rmInst->instName);
1931 if (rmInst->instType == Rm_instType_SERVER) {
1932 Rm_osalLog("Type: Server\n");
1933 }
1934 else if (rmInst->instType == Rm_instType_CLIENT_DELEGATE) {
1935 Rm_osalLog("Type: Client Delegate\n");
1936 }
1937 else {
1938 Rm_osalLog("Type: Client\n");
1939 }
1941 if (transportList) {
1942 Rm_osalLog("\nRegistered Transports:\n");
1943 while (transportList) {
1944 Rm_osalLog(" Remote instName: %s\n", transportList->remoteInstName);
1945 if (transportList->remoteInstType == Rm_instType_SERVER) {
1946 Rm_osalLog(" Remote instType: Server\n");
1947 }
1948 else if (transportList->remoteInstType == Rm_instType_CLIENT_DELEGATE) {
1949 Rm_osalLog(" Remote instType: Client Delegate\n");
1950 }
1951 else {
1952 Rm_osalLog(" Remote instType: Client\n");
1953 }
1954 Rm_osalLog(" appTransportHandle: 0x%08x\n", transportList->appTransportHandle);
1955 Rm_osalLog("\n");
1956 transportList = transportList->nextTransport;
1957 }
1958 }
1960 if (transactionQ) {
1961 Rm_osalLog("\nQueued Service Transactions:\n");
1962 while (transactionQ) {
1963 Rm_osalLog(" Service type: %d\n", transactionQ->type);
1964 Rm_osalLog(" Service ID: %d\n", transactionQ->localId);
1965 Rm_osalLog(" Service srcInstName %s\n", transactionQ->serviceSrcInstName);
1966 Rm_osalLog(" Service state: %d\n", transactionQ->state);
1967 Rm_osalLog(" Resource name: %s\n", transactionQ->resourceInfo.name);
1968 Rm_osalLog(" Resource base: %d\n", transactionQ->resourceInfo.base);
1969 Rm_osalLog(" Resource length: %d\n", transactionQ->resourceInfo.length);
1970 Rm_osalLog(" Resource alignment: %d\n", transactionQ->resourceInfo.alignment);
1971 Rm_osalLog(" Resource NS name: %s\n", transactionQ->resourceInfo.nameServerName);
1972 Rm_osalLog("\n");
1973 transactionQ = transactionQ->nextTransaction;
1974 }
1975 }
1976 }
1978 /* FUNCTION PURPOSE: RM instance creation and initialization
1979 ***********************************************************************
1980 * DESCRIPTION: Returns a new RM instance created and initialized
1981 * using the parameters provided via the initCfg
1982 * structure.
1983 */
1984 Rm_Handle Rm_init(const Rm_InitCfg *initCfg, int32_t *result)
1985 {
1986 Rm_Inst *rmInst;
1987 void *globalResourceDtb = NULL;
1988 void *linuxResourceDtb = NULL;
1989 bool addLinux = false;
1991 *result = RM_OK;
1993 if ((initCfg->instName == NULL) ||
1994 ((strlen(initCfg->instName) + 1) > RM_NAME_MAX_CHARS)) {
1995 *result = RM_ERROR_INVALID_INST_NAME;
1996 return (NULL);
1997 }
1999 if (initCfg->instType >= Rm_instType_LAST) {
2000 *result = RM_ERROR_INVALID_INST_TYPE;
2001 }
2003 /* Create and initialize instance */
2004 rmInst = Rm_osalMalloc (sizeof(Rm_Inst));
2005 memset ((void *) rmInst, 0, sizeof(Rm_Inst));
2006 rmInst->isLocked = false;
2007 rmInst->registeredWithDelegateOrServer = false;
2008 rmInst->transactionSeqNum = transactionInitSequenceNum();
2010 rmInst->instType = initCfg->instType;
2011 strncpy (rmInst->instName, initCfg->instName, RM_NAME_MAX_CHARS);
2013 if (rmInst->instType == Rm_instType_SERVER) {
2014 if (!initCfg->instCfg.serverCfg.globalResourceList ||
2015 !initCfg->instCfg.serverCfg.globalPolicy) {
2016 *result = RM_ERROR_INVALID_SERVER_CONFIGURATION;
2017 Rm_osalFree((void *)rmInst, sizeof(Rm_Inst));
2018 return(NULL);
2019 }
2021 rmInst->policy = initCfg->instCfg.serverCfg.globalPolicy;
2022 fdt_open_into(rmInst->policy, rmInst->policy, fdt_totalsize(rmInst->policy));
2024 if (initCfg->instCfg.serverCfg.linuxDtb) {
2025 linuxResourceDtb = initCfg->instCfg.serverCfg.linuxDtb;
2026 fdt_open_into(linuxResourceDtb, linuxResourceDtb, fdt_totalsize(linuxResourceDtb));
2027 addLinux = true;
2028 }
2030 /* Create valid instance list from policy. Must be done prior to parsing
2031 * GRL so that Linux resources can be reserved correctly */
2032 rmInst->validInstances = rmPolicyCreateValidInstTree(rmInst->policy, addLinux, result);
2033 /* Validate policy assignment strings */
2034 *result = rmPolicyValidatePolicy(rmInst->policy, rmInst->validInstances);
2036 rmInst->nameServer = rmNameServerInit();
2038 globalResourceDtb = initCfg->instCfg.serverCfg.globalResourceList;
2039 fdt_open_into(globalResourceDtb, globalResourceDtb, fdt_totalsize(globalResourceDtb));
2041 if ((*result = initializeAllocators(rmInst, globalResourceDtb, linuxResourceDtb)) == RM_OK) {
2042 *result = rmPolicyValidatePolicyResourceNames(rmInst->policy, (void *)rmInst->allocators);
2043 }
2044 if (*result < RM_OK) {
2045 Rm_osalFree((void *)rmInst, sizeof(Rm_Inst));
2046 return(NULL);
2047 }
2048 }
2050 if ((rmInst->instType == Rm_instType_CLIENT) &&
2051 (initCfg->instCfg.clientCfg.staticPolicy)) {
2052 rmInst->staticInfo.staticPolicy = initCfg->instCfg.clientCfg.staticPolicy;
2053 }
2054 else if ((rmInst->instType == Rm_instType_CLIENT_DELEGATE) &&
2055 (initCfg->instCfg.cdCfg.staticPolicy)) {
2056 rmInst->staticInfo.staticPolicy = initCfg->instCfg.cdCfg.staticPolicy;
2057 }
2058 if (rmInst->staticInfo.staticPolicy) {
2059 fdt_open_into(rmInst->staticInfo.staticPolicy, rmInst->staticInfo.staticPolicy,
2060 fdt_totalsize(rmInst->staticInfo.staticPolicy));
2061 rmInst->staticInfo.staticValidInstTree = rmPolicyCreateValidInstTree(rmInst->staticInfo.staticPolicy,
2062 addLinux, result);
2063 if (*result == RM_OK) {
2064 /* Validate policy assignment strings */
2065 *result = rmPolicyValidatePolicy(rmInst->staticInfo.staticPolicy, rmInst->staticInfo.staticValidInstTree);
2066 }
2067 if (*result != RM_OK) {
2068 if (rmInst->staticInfo.staticValidInstTree) {
2069 rmPolicyFreeValidInstTree(rmInst->staticInfo.staticValidInstTree);
2070 }
2071 Rm_osalFree((void *)rmInst, sizeof(Rm_Inst));
2072 rmInst = NULL;
2073 }
2074 }
2075 return ((Rm_Handle) rmInst);
2076 }
2078 /* FUNCTION PURPOSE: Returns RM version information
2079 ***********************************************************************
2080 */
2081 uint32_t Rm_getVersion (void)
2082 {
2083 return RM_VERSION_ID;
2084 }
2086 /* FUNCTION PURPOSE: Returns RM version string
2087 ***********************************************************************
2088 */
2089 const char* Rm_getVersionStr (void)
2090 {
2091 return rmVersionStr;
2092 }