/** * @file rm.c * * @brief * This is the Resource Manager source. * * \par * ============================================================================ * @n (C) Copyright 2012-2013, Texas Instruments, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * Neither the name of Texas Instruments Incorporated nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * \par */ /* Standard includes */ #include #include /* RM external includes */ #include #include #include #include /* RM internal includes */ #include #include #include #include #include #include /* RM LIBFDT includes */ #include /* RM OSAL layer */ #include /********************************************************************** ************************** Globals *********************************** **********************************************************************/ /* Global Variable which describes the RM Version Information */ const char rmVersionStr[] = RM_VERSION_STR ":" __DATE__ ":" __TIME__; /********************************************************************** ************************ Local Functions ***************************** **********************************************************************/ /* FUNCTION PURPOSE: Initializes a RM inst's transaction sequence number *********************************************************************** * DESCRIPTION: The RM instance transaction sequence number can never * have a value of 0 to avoid conflicts with transactions * that have a remoteOriginatingId of 0 (transaction ID * will be used as the remoteOriginatingId for * transactions that are responses to requests). */ static uint32_t transactionInitSequenceNum(void) { return (1); } /* FUNCTION PURPOSE: Provides a sequence number for new transactions *********************************************************************** * DESCRIPTION: Returns a sequence number for a new transaction * specific to a RM instance. Handles rollover of * sequence number. */ static uint32_t transactionGetSequenceNum(Rm_Inst *rmInst) { rmInst->transactionSeqNum++; if (!rmInst->transactionSeqNum) { rmInst->transactionSeqNum++; } return (rmInst->transactionSeqNum); } /* FUNCTION PURPOSE: Creates a resource request packet *********************************************************************** * DESCRIPTION: Returns a RM packet handle that points to a RM * resource request packet that has been prepared * for sending to another RM instance. The packet * is allocated via the rmAllocPkt API using the * appTransport handle provided by the application */ void createResourceReqPkt(Rm_Packet *rmPkt, char *localInstName, Rm_Transaction *transaction) { Rm_ResourceRequestPkt *resourceReqPkt = NULL; rmPkt->pktType = Rm_pktType_RESOURCE_REQUEST; resourceReqPkt = (Rm_ResourceRequestPkt *) rmPkt->data; resourceReqPkt->requestId = transaction->localId; if (transaction->type == Rm_service_RESOURCE_ALLOCATE_INIT) { resourceReqPkt->resourceReqType = Rm_resReqPktType_ALLOCATE_INIT; } else if (transaction->type == Rm_service_RESOURCE_ALLOCATE_USE) { resourceReqPkt->resourceReqType = Rm_resReqPktType_ALLOCATE_USE; } else if (transaction->type == Rm_service_RESOURCE_FREE) { resourceReqPkt->resourceReqType = Rm_resReqPktType_FREE; } else if (transaction->type == Rm_service_RESOURCE_GET_BY_NAME) { resourceReqPkt->resourceReqType = Rm_resReqPktType_GET_NAMED; } strncpy(resourceReqPkt->pktSrcInstName, localInstName, RM_NAME_MAX_CHARS); strncpy(resourceReqPkt->serviceSrcInstName, transaction->serviceSrcInstName, RM_NAME_MAX_CHARS); memcpy ((void *)&(resourceReqPkt->resourceInfo), (void *)&(transaction->resourceInfo), sizeof(Rm_ResourceInfo)); } /* FUNCTION PURPOSE: Creates a resource response packet *********************************************************************** * DESCRIPTION: Returns a RM packet handle that points to a RM * resource response packet that has been prepared * for sending to another RM instance. The packet * is allocated via the rmAllocPkt API using the * appTransport handle provided by the application */ void createResourceResponsePkt(Rm_Packet *rmPkt, Rm_Transaction *transaction) { Rm_ResourceResponsePkt *resourceRespPkt = NULL; rmPkt->pktType = Rm_pktType_RESOURCE_RESPONSE; resourceRespPkt = (Rm_ResourceResponsePkt *)rmPkt->data; resourceRespPkt->responseId = transaction->remoteOriginatingId; resourceRespPkt->requestState = transaction->state; memcpy ((void *)&(resourceRespPkt->resourceInfo), (void *)&(transaction->resourceInfo), sizeof(Rm_ResourceInfo)); } /* FUNCTION PURPOSE: Creates a NameServer request packet *********************************************************************** * DESCRIPTION: Returns a RM packet handle that points to a RM * NameServer request packet that has been prepared * for sending to another RM instance. The packet * is allocated via the rmAllocPkt API using the * appTransport handle provided by the application */ void createNsRequestPkt(Rm_Packet *rmPkt, char *localInstName, Rm_Transaction *transaction) { Rm_NsRequestPkt *nsReqPkt = NULL; rmPkt->pktType = Rm_pktType_NAMESERVER_REQUEST; nsReqPkt = (Rm_NsRequestPkt *)rmPkt->data; nsReqPkt->requestId = transaction->localId; if (transaction->type == Rm_service_RESOURCE_MAP_TO_NAME) { nsReqPkt->nsRequestType = Rm_nsReqPktType_MAP_RESOURCE; } else if (transaction->type == Rm_service_RESOURCE_UNMAP_NAME) { nsReqPkt->nsRequestType = Rm_nsReqPktType_UNMAP_RESOURCE; } strncpy(nsReqPkt->pktSrcInstName, localInstName, RM_NAME_MAX_CHARS); strncpy(nsReqPkt->serviceSrcInstName, transaction->serviceSrcInstName, RM_NAME_MAX_CHARS); memcpy ((void *)&(nsReqPkt->resourceInfo), (void *)&(transaction->resourceInfo), sizeof(Rm_ResourceInfo)); } /* FUNCTION PURPOSE: Creates a NameServer response packet *********************************************************************** * DESCRIPTION: Returns a RM packet handle that points to a RM * NameServer response packet that has been prepared * for sending to another RM instance. The packet * is allocated via the rmAllocPkt API using the * appTransport handle provided by the application */ void createNsResponsePkt(Rm_Packet *rmPkt, Rm_Transaction *transaction) { Rm_NsResponsePkt *nsRespPkt = NULL; rmPkt->pktType = Rm_pktType_NAMESERVER_RESPONSE; nsRespPkt = (Rm_NsResponsePkt *)rmPkt->data; nsRespPkt->responseId = transaction->remoteOriginatingId; nsRespPkt->requestState = transaction->state; } /* FUNCTION PURPOSE: Issues a service response to application *********************************************************************** * DESCRIPTION: Provides a service response back to the application * using the service callback function provided to * the RM instance at the time of the service request. */ static void serviceResponder (Rm_Inst *rmInst, Rm_Transaction *transaction) { Rm_ServiceRespInfo serviceResponse; serviceResponse.rmHandle = (Rm_Handle)rmInst; /* The responseTransaction will contain the resultant state details of * the requestTransaction's service request */ serviceResponse.serviceState = transaction->state; /* Pass back the ID that was provided to the component when it requested * the service */ serviceResponse.serviceId = transaction->localId; /* Service was approved and service was an allocate request. The resource * data is passed back to the component */ if ((serviceResponse.serviceState == RM_SERVICE_APPROVED) && ((transaction->type == Rm_service_RESOURCE_ALLOCATE_INIT) || (transaction->type == Rm_service_RESOURCE_ALLOCATE_USE) || (transaction->type == Rm_service_RESOURCE_GET_BY_NAME))) { strncpy(serviceResponse.resourceName, transaction->resourceInfo.name, RM_NAME_MAX_CHARS); serviceResponse.resourceBase = transaction->resourceInfo.base; serviceResponse.resourceLength = transaction->resourceInfo.length; } if (transaction->callback.serviceCallback) { /* Issue the callback to the requesting component with the response information */ transaction->callback.serviceCallback(&serviceResponse); /* Delete the transaction from the transaction queue */ rmTransactionQueueDelete(rmInst, transaction->localId); } else { rmServiceInternalCallback((Rm_Handle)rmInst); } return; } /* FUNCTION PURPOSE: Sends RM response packets *********************************************************************** * DESCRIPTION: Sends RM response packets to RM instance's that sent * RM request packets to the RM instance. The response * is sent via the RM transport API which is plugged * with an application created transport path. */ static void transactionResponder (Rm_Inst *rmInst, Rm_Transaction *transaction) { Rm_Transport *dstTransport = NULL; Rm_Packet *rmPkt = NULL; Rm_PacketHandle pktHandle = NULL; if (dstTransport = rmTransportFindRemoteName(rmInst->transports, transaction->pktSrcInstName)) { rmPkt = dstTransport->callouts.rmAllocPkt(dstTransport->appTransportHandle, sizeof(Rm_Packet), &pktHandle); if (!rmPkt || !pktHandle) { transaction->state = RM_ERROR_TRANSPORT_ALLOC_PKT_ERROR; goto errorExit; } switch (transaction->type) { case Rm_service_RESOURCE_ALLOCATE_INIT: case Rm_service_RESOURCE_ALLOCATE_USE: case Rm_service_RESOURCE_FREE: case Rm_service_RESOURCE_GET_BY_NAME: createResourceResponsePkt(rmPkt, transaction); break; case Rm_service_RESOURCE_MAP_TO_NAME: case Rm_service_RESOURCE_UNMAP_NAME: createNsResponsePkt(rmPkt, transaction); break; } if (dstTransport->callouts.rmSendPkt(dstTransport->appTransportHandle, pktHandle) < RM_OK) { transaction->state = RM_ERROR_TRANSPORT_SEND_ERROR; goto errorExit; } /* Response packet sent: Delete transaction from queue */ rmTransactionQueueDelete(rmInst, transaction->localId); } else { transaction->state = RM_ERROR_TRANSPORT_REMOTE_HNDL_NOT_REGD; } errorExit: /* Do not delete transaction on transport error. Transport rrror transactions should be visible * from Rm_printInstanceStatus() */ return; } /* FUNCTION PURPOSE: Sends RM request packets *********************************************************************** * DESCRIPTION: Sends RM request packets to RM instance's that are * capable of forwarding or validating service requests. * The request is sent via the RM transport API which is * plugged with an application created transport path. */ static void transactionForwarder (Rm_Inst *rmInst, Rm_Transaction *transaction) { Rm_Transport *dstTransport = NULL; Rm_Packet *rmPkt = NULL; Rm_PacketHandle pktHandle = NULL; if (rmInst->instType == Rm_instType_CLIENT) { dstTransport = rmTransportFindRemoteInstType(rmInst->transports, Rm_instType_CLIENT_DELEGATE); if (!dstTransport) { dstTransport = rmTransportFindRemoteInstType(rmInst->transports, Rm_instType_SERVER); } } else if (rmInst->instType == Rm_instType_CLIENT_DELEGATE) { dstTransport = rmTransportFindRemoteInstType(rmInst->transports, Rm_instType_SERVER); } /* Just queue transaction if transport hasn't been registered. Do not return error */ if (dstTransport) { rmPkt = dstTransport->callouts.rmAllocPkt(dstTransport->appTransportHandle, sizeof(Rm_Packet), &pktHandle); if (!rmPkt || !pktHandle) { transaction->state = RM_ERROR_TRANSPORT_ALLOC_PKT_ERROR; goto errorExit; } switch (transaction->type) { case Rm_service_RESOURCE_ALLOCATE_INIT: case Rm_service_RESOURCE_ALLOCATE_USE: case Rm_service_RESOURCE_FREE: case Rm_service_RESOURCE_GET_BY_NAME: createResourceReqPkt(rmPkt, rmInst->instName, transaction); break; case Rm_service_RESOURCE_MAP_TO_NAME: case Rm_service_RESOURCE_UNMAP_NAME: createNsRequestPkt(rmPkt, rmInst->instName, transaction); break; } if (dstTransport->callouts.rmSendPkt(dstTransport->appTransportHandle, pktHandle) < RM_OK) { transaction->state = RM_ERROR_TRANSPORT_SEND_ERROR; goto errorExit; } transaction->hasBeenForwarded = RM_TRUE; /* Transaction not deleted. Waiting for response from RM CD or Server */ } return; errorExit: /* Do not delete transaction on transport error. Transport rrror transactions should be visible * from Rm_printInstanceStatus() */ return; } /* FUNCTION PURPOSE: Handles static allocation requests *********************************************************************** * DESCRIPTION: Validates allocation requests received on CDs and * Clients prior to the instance's registering * with a Server. The allocation request is validated * against a static policy. */ static void staticAllocationHandler (Rm_Handle rmHandle, Rm_Transaction *transaction) { Rm_Inst *rmInst = (Rm_Inst *)rmHandle; void *staticPolicy = rmPolicyGetPolicy(rmHandle); Rm_PolicyCheckCfg privCheckCfg; int32_t result; if (staticPolicy) { if ((transaction->type == Rm_service_RESOURCE_ALLOCATE_INIT) || (transaction->type == Rm_service_RESOURCE_ALLOCATE_USE)) { /* Check request against startup policy */ memset((void *)&privCheckCfg, 0, sizeof(Rm_PolicyCheckCfg)); if (transaction->type == Rm_service_RESOURCE_ALLOCATE_INIT) { privCheckCfg.type = Rm_policyCheck_INIT; } else { privCheckCfg.type = Rm_policyCheck_USE; } privCheckCfg.policyDtb = staticPolicy; privCheckCfg.validInstNode = rmPolicyGetValidInstNode(rmHandle, rmInst->instName); privCheckCfg.resourceOffset = rmPolicyGetResourceOffset(staticPolicy, transaction->resourceInfo.name); privCheckCfg.resourceBase = transaction->resourceInfo.base; privCheckCfg.resourceLength = transaction->resourceInfo.length; if (rmPolicyCheckPrivilege(&privCheckCfg, &result)) { transaction->state = RM_SERVICE_APPROVED_STATIC; } else if (result == RM_OK) { /* Privilege check returned false without error */ transaction->state = RM_SERVICE_DENIED_BY_STATIC_POLICY; } else { /* Privilege check returned false with error */ transaction->state = result; } } else { transaction->state = RM_SERVICE_DENIED_INVALID_STATIC_REQUEST; } } else { transaction->state = RM_ERROR_REQ_FAILED_NO_STATIC_POLICY; } } /* FUNCTION PURPOSE: Arbitrates allocation service requests *********************************************************************** * DESCRIPTION: Issues a set of allocator operations in order to * handle a received allocation request. Allocation * requests are always forwarded to the Server on Client * CD instances. If a request is made with a NameServer * name the resource base and length parameters are * retrieved from the NameServer prior to the allocation * attempt. */ static void allocationHandler (Rm_Inst *rmInst, Rm_Transaction *transaction) { Rm_AllocatorOpInfo opInfo; Rm_NameServerObjCfg nameServerObjCfg; int32_t retVal = transaction->state; if (rmInst->instType == Rm_instType_CLIENT_DELEGATE) { transactionForwarder(rmInst, transaction); } else if ((rmInst->instType == Rm_instType_SERVER)|| (rmInst->instType == Rm_instType_SHARED_SERVER)) { memset((void *)&opInfo, 0, sizeof(Rm_AllocatorOpInfo)); opInfo.policy = rmInst->u.server.globalPolicy; opInfo.resourceInfo = &transaction->resourceInfo; opInfo.serviceSrcInstNode = rmPolicyGetValidInstNode((Rm_Handle)rmInst, transaction->serviceSrcInstName); if (opInfo.serviceSrcInstNode) { switch (transaction->type) { case Rm_service_RESOURCE_ALLOCATE_INIT: RM_policy_SET_PERM(opInfo.allocType, RM_POLICY_PERM_INIT_SHIFT, 1); break; case Rm_service_RESOURCE_ALLOCATE_USE: RM_policy_SET_PERM(opInfo.allocType, RM_POLICY_PERM_USE_SHIFT, 1); break; } /* Populated NameServer name has precedence over base */ if (strlen(transaction->resourceInfo.nameServerName) > 0) { if ((transaction->resourceInfo.base == 0) && (transaction->resourceInfo.length == 0) && (transaction->resourceInfo.alignment == 0)) { if (rmInst->instType == Rm_instType_SHARED_SERVER) { rmNameServerTreeInv(rmInst->u.server.nameServer); } memset((void *)&nameServerObjCfg, 0, sizeof(Rm_NameServerObjCfg)); nameServerObjCfg.nameServerTree = rmInst->u.server.nameServer; nameServerObjCfg.nodeCfg.objName = transaction->resourceInfo.nameServerName; if ((retVal = rmNameServerFindObject(&nameServerObjCfg)) == RM_SERVICE_PROCESSING) { strncpy(transaction->resourceInfo.name, nameServerObjCfg.nodeCfg.resourceName, RM_NAME_MAX_CHARS); transaction->resourceInfo.base = nameServerObjCfg.nodeCfg.resourceBase; transaction->resourceInfo.length = nameServerObjCfg.nodeCfg.resourceLength; } } else { retVal = RM_ERROR_NS_NAME_AND_RES_VAL_CONFLICT; } } if (retVal == RM_SERVICE_PROCESSING) { if (transaction->resourceInfo.base == RM_RESOURCE_BASE_UNSPECIFIED) { opInfo.operation = Rm_allocatorOp_PRE_ALLOCATE; retVal = rmAllocatorOperation((Rm_Handle)rmInst, &opInfo); } if (retVal == RM_SERVICE_PROCESSING) { opInfo.operation = Rm_allocatorOp_ALLOCATE; retVal = rmAllocatorOperation((Rm_Handle)rmInst, &opInfo); } } } else { retVal = RM_SERVICE_DENIED_INST_NAME_NOT_VALID; } transaction->state = retVal; } } /* FUNCTION PURPOSE: Arbitrates free service requests *********************************************************************** * DESCRIPTION: Issues a set of allocator operations in order to * handle a received free request. Free * requests are always forwarded to the Server on Client * CD instances. If a request is made with a NameServer * name the resource base and length parameters are * retrieved from the NameServer prior to the free * attempt. */ static void freeHandler (Rm_Inst *rmInst, Rm_Transaction *transaction) { Rm_AllocatorOpInfo opInfo; Rm_NameServerObjCfg nameServerObjCfg; int32_t retVal = transaction->state; if (rmInst->instType == Rm_instType_CLIENT_DELEGATE) { transactionForwarder(rmInst, transaction); } else if ((rmInst->instType == Rm_instType_SERVER) || (rmInst->instType == Rm_instType_SHARED_SERVER)) { memset((void *)&opInfo, 0, sizeof(Rm_AllocatorOpInfo)); opInfo.policy = rmInst->u.server.globalPolicy; opInfo.resourceInfo = &transaction->resourceInfo; opInfo.serviceSrcInstNode = rmPolicyGetValidInstNode((Rm_Handle)rmInst, transaction->serviceSrcInstName); if (opInfo.serviceSrcInstNode) { /* Populated NameServer name has precedence over base */ if (strlen(transaction->resourceInfo.nameServerName) > 0) { if ((transaction->resourceInfo.base == 0) && (transaction->resourceInfo.length == 0) && (transaction->resourceInfo.alignment == 0)) { if (rmInst->instType == Rm_instType_SHARED_SERVER) { rmNameServerTreeInv(rmInst->u.server.nameServer); } memset((void *)&nameServerObjCfg, 0, sizeof(Rm_NameServerObjCfg)); nameServerObjCfg.nameServerTree = rmInst->u.server.nameServer; nameServerObjCfg.nodeCfg.objName = transaction->resourceInfo.nameServerName; if ((retVal = rmNameServerFindObject(&nameServerObjCfg)) == RM_SERVICE_PROCESSING) { strncpy(transaction->resourceInfo.name, nameServerObjCfg.nodeCfg.resourceName, RM_NAME_MAX_CHARS); transaction->resourceInfo.base = nameServerObjCfg.nodeCfg.resourceBase; transaction->resourceInfo.length = nameServerObjCfg.nodeCfg.resourceLength; } } else { retVal = RM_ERROR_NS_NAME_AND_RES_VAL_CONFLICT; } } if(retVal == RM_SERVICE_PROCESSING) { opInfo.operation = Rm_allocatorOp_FREE; retVal = rmAllocatorOperation((Rm_Handle)rmInst, &opInfo); } } else { retVal = RM_SERVICE_DENIED_INST_NAME_NOT_VALID; } transaction->state = retVal; } } /* FUNCTION PURPOSE: Client transaction handling process *********************************************************************** * DESCRIPTION: Client process for handling transactions created * from services received via the service handle or the * transport. The Client process: * - Performs static allocations if no transport * to CD or Server has been registered * - Forwards all service requests to CD or Server * once transport has been registered */ static void clientProcess (Rm_Inst *rmInst, Rm_Transaction *transaction) { Rm_Transaction *transQ = rmInst->transactionQueue; if (!rmInst->registeredWithDelegateOrServer) { staticAllocationHandler((Rm_Handle)rmInst, transaction); } else { if (transaction->state == RM_SERVICE_PROCESSING) { /* Forward all new transactions to CD or Server */ transactionForwarder(rmInst, transaction); } else { /* Transaction validated. Return result. */ serviceResponder(rmInst, transaction); } /* Forward any queued static requests that weren't forwarded */ while(transQ) { if ((transQ->state == RM_SERVICE_APPROVED_STATIC) && (!transQ->hasBeenForwarded)) { transactionForwarder(rmInst, transQ); } transQ = transQ->nextTransaction; } } /* Let call stack return transaction result app via Rm_serviceHandler */ } /* FUNCTION PURPOSE: Client Delegate transaction handling process *********************************************************************** * DESCRIPTION: Client Delegate process for handling transactions created * from services received via the service handle or the * transport. The Client Delegate process: * - Performs static allocations if no transport * to Server has been registered * - Forwards all NameServer related service requests * to Server once transport has been registered * - Attempts to complete resource service requests * received from registered Clients */ static void clientDelegateProcess (Rm_Inst *rmInst, Rm_Transaction *transaction) { Rm_Transaction *transQ = rmInst->transactionQueue; if (!rmInst->registeredWithDelegateOrServer) { if ((transaction->state == RM_SERVICE_PROCESSING) && (strncmp(transaction->serviceSrcInstName, rmInst->instName, RM_NAME_MAX_CHARS) == 0)) { staticAllocationHandler((Rm_Handle)rmInst, transaction); } /* Everything else left in transaction queue for forwarding once transport to * Server is registered */ } else { if ((transaction->state == RM_SERVICE_PROCESSING) || (transaction->state == RM_SERVICE_APPROVED_STATIC)) { if ((transaction->type == Rm_service_RESOURCE_MAP_TO_NAME) || (transaction->type == Rm_service_RESOURCE_GET_BY_NAME) || (transaction->type == Rm_service_RESOURCE_UNMAP_NAME)) { /* Forward all NameServer requests. */ transactionForwarder(rmInst, transaction); } else if (transaction->type == Rm_service_RESOURCE_FREE) { freeHandler(rmInst, transaction); } else { allocationHandler(rmInst, transaction); } } else { /* Transaction validated. Return result. */ if (strncmp(transaction->serviceSrcInstName, rmInst->instName, RM_NAME_MAX_CHARS)) { /* Transaction did not originate on this instance */ transactionResponder(rmInst, transaction); } else { /* Transaction originated on this instance */ serviceResponder(rmInst, transaction); } } /* Forward any queued static requests (local and received from any registered * Clients that weren't forwarded */ while(transQ) { if (((transQ->state == RM_SERVICE_PROCESSING) || (transQ->state == RM_SERVICE_APPROVED_STATIC)) && (!transQ->hasBeenForwarded)) { transactionForwarder(rmInst, transQ); } transQ = transQ->nextTransaction; } } } /* FUNCTION PURPOSE: Server transaction handling process *********************************************************************** * DESCRIPTION: Server process for handling transactions created * from services received via the service handle or the * transport. The Server process: * - Validates all service requests received from * the service handle and registered CDs and * Clients */ static void serverProcess (Rm_Inst *rmInst, Rm_Transaction *transaction) { Rm_NameServerObjCfg nameServerObjCfg; switch (transaction->type) { case Rm_service_RESOURCE_ALLOCATE_INIT: case Rm_service_RESOURCE_ALLOCATE_USE: allocationHandler(rmInst, transaction); break; case Rm_service_RESOURCE_FREE: freeHandler(rmInst, transaction); break; case Rm_service_RESOURCE_MAP_TO_NAME: case Rm_service_RESOURCE_GET_BY_NAME: case Rm_service_RESOURCE_UNMAP_NAME: if (rmInst->u.server.nameServer) { if (rmInst->instType == Rm_instType_SHARED_SERVER) { rmNameServerTreeInv(rmInst->u.server.nameServer); } memset((void *)&nameServerObjCfg, 0, sizeof(Rm_NameServerObjCfg)); nameServerObjCfg.nameServerTree = rmInst->u.server.nameServer; nameServerObjCfg.nodeCfg.objName = transaction->resourceInfo.nameServerName; if (transaction->type == Rm_service_RESOURCE_MAP_TO_NAME) { nameServerObjCfg.nodeCfg.resourceName = transaction->resourceInfo.name; nameServerObjCfg.nodeCfg.resourceBase= transaction->resourceInfo.base; nameServerObjCfg.nodeCfg.resourceLength = transaction->resourceInfo.length; transaction->state = rmNameServerAddObject(&nameServerObjCfg); } else if (transaction->type == Rm_service_RESOURCE_GET_BY_NAME) { if ((transaction->state = rmNameServerFindObject(&nameServerObjCfg)) == RM_SERVICE_PROCESSING) { strncpy(transaction->resourceInfo.name, nameServerObjCfg.nodeCfg.resourceName, RM_NAME_MAX_CHARS); transaction->resourceInfo.base = nameServerObjCfg.nodeCfg.resourceBase; transaction->resourceInfo.length = nameServerObjCfg.nodeCfg.resourceLength; transaction->state = RM_SERVICE_APPROVED; } } else if (transaction->type == Rm_service_RESOURCE_UNMAP_NAME) { transaction->state = rmNameServerDeleteObject(&nameServerObjCfg); } if (rmInst->instType == Rm_instType_SHARED_SERVER) { rmNameServerTreeWb(rmInst->u.server.nameServer); } } else { transaction->state = RM_ERROR_NAMESERVER_DOES_NOT_EXIST; } break; } /* Source of shared server transaction will always be local. */ if (rmInst->instType != Rm_instType_SHARED_SERVER) { if (strncmp(transaction->serviceSrcInstName, rmInst->instName, RM_NAME_MAX_CHARS)) { /* Source of transaction was not Server, return transaction via responder */ transactionResponder(rmInst, transaction); } } /* Otherwise let call stack return transaction result app via Rm_serviceHandler */ } /********************************************************************** ********************** Internal Functions **************************** **********************************************************************/ /* FUNCTION PURPOSE: Adds a transaction *********************************************************************** * DESCRIPTION: Returns a pointer to a newly created transaction. * The transaction is created based on a new service * request received via the service API or the * transport API (service forwarded from another instance) */ Rm_Transaction *rmTransactionQueueAdd(Rm_Inst *rmInst) { Rm_Transaction *transactionQueue = rmInst->transactionQueue; Rm_Transaction *newTransaction = NULL; newTransaction = Rm_osalMalloc(sizeof(Rm_Transaction)); if (newTransaction) { memset((void *)newTransaction, 0, sizeof(Rm_Transaction)); newTransaction->localId = transactionGetSequenceNum(rmInst); newTransaction->nextTransaction = NULL; if (transactionQueue) { while (transactionQueue->nextTransaction) { transactionQueue = transactionQueue->nextTransaction; } transactionQueue->nextTransaction = newTransaction; } else { rmInst->transactionQueue = newTransaction; } } return (newTransaction); } /* FUNCTION PURPOSE: Finds a transaction *********************************************************************** * DESCRIPTION: Returns a pointer to a transaction resident * in the transaction queue that matches the provided * transaction ID. */ Rm_Transaction *rmTransactionQueueFind(Rm_Inst *rmInst, uint32_t transactionId) { Rm_Transaction *transaction = rmInst->transactionQueue; while (transaction) { if (transaction->localId == transactionId) { break; } transaction = transaction->nextTransaction; } return (transaction); } /* FUNCTION PURPOSE: Deletes a transaction *********************************************************************** * DESCRIPTION: Deletes the transaction with the provided transaction * ID from the instance's transaction queue. */ int32_t rmTransactionQueueDelete(Rm_Inst *rmInst, uint32_t transactionId) { Rm_Transaction *transaction = rmInst->transactionQueue; Rm_Transaction *prevTransaction = NULL; int32_t retVal = RM_OK; while (transaction) { if (transaction->localId == transactionId) { break; } prevTransaction = transaction; transaction = transaction->nextTransaction; } if (transaction) { if (prevTransaction == NULL) { /* Transaction at start of queue. Map second transaction to start of queue * as long as more than one transactions. */ rmInst->transactionQueue = transaction->nextTransaction; } else { /* Transaction in middle or end of queue. */ prevTransaction->nextTransaction = transaction->nextTransaction; } Rm_osalFree((void *)transaction, sizeof(Rm_Transaction)); } else { retVal = RM_ERROR_SERVICE_TRANS_DOES_NOT_EXIST; } return (retVal); } /* FUNCTION PURPOSE: Routes a transaction for processing *********************************************************************** * DESCRIPTION: Routes a received transaction to the appropriate * instance processing routine */ void rmProcessRouter (Rm_Inst *rmInst, Rm_Transaction *transaction) { if (rmInst->instType == Rm_instType_CLIENT) { clientProcess(rmInst, transaction); } else if (rmInst->instType == Rm_instType_CLIENT_DELEGATE) { clientDelegateProcess(rmInst, transaction); } else if ((rmInst->instType == Rm_instType_SERVER) || (rmInst->instType == Rm_instType_SHARED_SERVER)) { serverProcess(rmInst, transaction); } } /********************************************************************** ********************** Application visible APIs ********************** **********************************************************************/ /* FUNCTION PURPOSE: Display status of managed resources *********************************************************************** * DESCRIPTION: Prints the status (allocate/free status, as well as * owners) for all resources managed by the RM * instance network. Also, prints the NameServer name * entries. The number of resource range owners is * returned as well. This function is only available on * server instances. */ int32_t Rm_resourceStatus(Rm_Handle rmServerHandle, int printResources) { Rm_Inst *rmInst = (Rm_Inst *)rmServerHandle; Rm_Allocator *allocator = NULL; Rm_Owner *owners; Rm_ResourceTree *treeRoot; Rm_ResourceNode *treeNode; int32_t totalResOwners = 0; void *key; RM_SS_INST_INV_ENTER_CS(key); RM_SC_INST_INV_ENTER_CS(key); if (rmInst->instType == Rm_instType_SHARED_CLIENT) { /* Transfer control to shared server instance */ rmInst = rmInst->u.sharedClient.sharedServerHandle; } if ((rmInst->instType == Rm_instType_SERVER) || (rmInst->instType == Rm_instType_SHARED_SERVER)) { allocator = rmInst->u.server.allocators; while (allocator) { RM_SS_OBJ_INV(allocator, Rm_Allocator); if (printResources) { Rm_osalLog("Resource: %s\n", allocator->resourceName); } treeRoot = allocator->allocatorRootEntry; if (rmInst->instType == Rm_instType_SHARED_SERVER) { rmResourceTreeInv(treeRoot); } RB_FOREACH(treeNode, _Rm_AllocatorResourceTree, treeRoot) { if (printResources) { if ((treeNode->base >= 65536) || ((treeNode->base + treeNode->length - 1) >= 65536)) { /* Print in hex if number is very large */ Rm_osalLog(" 0x%08x - 0x%08x ", treeNode->base, treeNode->base + treeNode->length - 1); } else { Rm_osalLog(" %10d - %10d ", treeNode->base, treeNode->base + treeNode->length - 1); } } if (treeNode->allocationCount == 0) { if (printResources) { Rm_osalLog("FREE\n"); } } else { owners = treeNode->ownerList; while (owners) { RM_SS_OBJ_INV(owners, Rm_Owner); if (printResources) { Rm_osalLog("%s ", owners->instNameNode->name); } totalResOwners++; owners = owners->nextOwner; } if (printResources) { Rm_osalLog("\n"); } } } allocator = allocator->nextAllocator; } if (printResources) { rmNameServerPrintObjects((Rm_Handle)rmInst); } } else { totalResOwners = RM_ERROR_INVALID_RES_STATUS_INSTANCE; } RM_SS_INST_WB_EXIT_CS(key); return(totalResOwners); } /* FUNCTION PURPOSE: Display status of a RM instance *********************************************************************** * DESCRIPTION: Prints the current status of various RM instance * properties such as the state of all transactions * in the transaction queue and registered transports */ void Rm_instanceStatus(Rm_Handle rmHandle) { Rm_Inst *rmInst = (Rm_Inst *)rmHandle; Rm_Transport *transportList = NULL; Rm_Transaction *transactionQ = NULL; void *key; RM_SS_INST_INV_ENTER_CS(key); RM_SC_INST_INV_ENTER_CS(key); Rm_osalLog("Instance name: %s\n", rmInst->instName); Rm_osalLog("Handle: 0x%08x\n", rmHandle); if (rmInst->instType == Rm_instType_SERVER) { Rm_osalLog("Type: Server\n"); } else if (rmInst->instType == Rm_instType_CLIENT_DELEGATE) { Rm_osalLog("Type: Client Delegate\n"); } else if (rmInst->instType == Rm_instType_CLIENT) { Rm_osalLog("Type: Client\n"); } else if (rmInst->instType == Rm_instType_SHARED_SERVER) { Rm_osalLog("Type: Shared Server\n"); } else if (rmInst->instType == Rm_instType_SHARED_CLIENT) { Rm_osalLog("Type: Shared Client\n"); Rm_osalLog("\nShared Server Properties:\n"); /* Transfer to Shared Server instance to print out transport and * transaction status */ rmInst = rmInst->u.sharedClient.sharedServerHandle; Rm_osalLog("Instance name: %s\n", rmInst->instName); Rm_osalLog("Handle: 0x%08x\n", rmHandle); } transportList = rmInst->transports; if (transportList) { Rm_osalLog("\nRegistered Transports:\n"); while (transportList) { RM_SS_OBJ_INV(transportList, Rm_Transport); Rm_osalLog(" Remote instName: %s\n", transportList->remoteInstName); if (transportList->remoteInstType == Rm_instType_SERVER) { Rm_osalLog(" Remote instType: Server\n"); } else if (transportList->remoteInstType == Rm_instType_CLIENT_DELEGATE) { Rm_osalLog(" Remote instType: Client Delegate\n"); } else { Rm_osalLog(" Remote instType: Client\n"); } Rm_osalLog(" appTransportHandle: 0x%08x\n", transportList->appTransportHandle); Rm_osalLog("\n"); transportList = transportList->nextTransport; } } transactionQ = rmInst->transactionQueue; if (transactionQ) { Rm_osalLog("\nQueued Service Transactions:\n"); while (transactionQ) { RM_SS_OBJ_INV(transactionQ, Rm_Transaction); Rm_osalLog(" Service type: %d\n", transactionQ->type); Rm_osalLog(" Service ID: %d\n", transactionQ->localId); Rm_osalLog(" Service srcInstName %s\n", transactionQ->serviceSrcInstName); Rm_osalLog(" Service state: %d\n", transactionQ->state); Rm_osalLog(" Resource name: %s\n", transactionQ->resourceInfo.name); Rm_osalLog(" Resource base: %d\n", transactionQ->resourceInfo.base); Rm_osalLog(" Resource length: %d\n", transactionQ->resourceInfo.length); Rm_osalLog(" Resource alignment: %d\n", transactionQ->resourceInfo.alignment); Rm_osalLog(" Resource NS name: %s\n", transactionQ->resourceInfo.nameServerName); Rm_osalLog("\n"); transactionQ = transactionQ->nextTransaction; } } RM_SS_INST_WB_EXIT_CS(key); } /* FUNCTION PURPOSE: RM instance creation and initialization *********************************************************************** * DESCRIPTION: Returns a new RM instance created and initialized * using the parameters provided via the initCfg * structure. */ Rm_Handle Rm_init(const Rm_InitCfg *initCfg, int32_t *result) { Rm_Inst *rmInst = NULL; Rm_Inst *sharedServerInst = NULL; void *globalResourceDtb = NULL; void *linuxResourceDtb = NULL; int addLinux = RM_FALSE; void *key; *result = RM_OK; if ((initCfg->instName == NULL) || ((strlen(initCfg->instName) + 1) > RM_NAME_MAX_CHARS)) { *result = RM_ERROR_INVALID_INST_NAME; goto errorExit; } if (initCfg->instType >= Rm_instType_LAST) { *result = RM_ERROR_INVALID_INST_TYPE; goto errorExit; } /* Create and initialize instance */ rmInst = Rm_osalMalloc (sizeof(Rm_Inst)); memset ((void *) rmInst, 0, sizeof(Rm_Inst)); rmInst->isLocked = RM_FALSE; rmInst->registeredWithDelegateOrServer = RM_FALSE; rmInst->transactionSeqNum = transactionInitSequenceNum(); rmInst->instType = initCfg->instType; strncpy (rmInst->instName, initCfg->instName, RM_NAME_MAX_CHARS); if ((rmInst->instType == Rm_instType_SERVER) || (rmInst->instType == Rm_instType_SHARED_SERVER)) { if (!initCfg->instCfg.serverCfg.globalResourceList || !initCfg->instCfg.serverCfg.globalPolicy) { *result = RM_ERROR_INVALID_SERVER_CONFIGURATION; goto errorExit; } rmInst->u.server.globalPolicy = initCfg->instCfg.serverCfg.globalPolicy; if (initCfg->instCfg.serverCfg.linuxDtb) { linuxResourceDtb = initCfg->instCfg.serverCfg.linuxDtb; addLinux = RM_TRUE; } /* Create valid instance list from policy. Must be done prior to parsing * GRL so that Linux resources can be reserved correctly */ rmInst->u.server.globalValidInstTree = rmPolicyCreateValidInstTree((Rm_Handle)rmInst, addLinux, result); if (*result == RM_OK) { *result = rmPolicyValidatePolicy((Rm_Handle)rmInst); } if (*result != RM_OK) { if (rmInst->u.server.globalValidInstTree) { rmPolicyFreeValidInstTree((Rm_Handle)rmInst); } goto errorExit; } else { rmNameServerInit((Rm_Handle)rmInst); globalResourceDtb = initCfg->instCfg.serverCfg.globalResourceList; if ((*result = rmAllocatorInitializeResources((Rm_Handle) rmInst, globalResourceDtb, linuxResourceDtb)) == RM_OK) { *result = rmPolicyValidatePolicyResourceNames((Rm_Handle)rmInst); } if (*result != RM_OK) { rmAllocatorDeleteResources((Rm_Handle)rmInst); rmNameServerDelete((Rm_Handle)rmInst); goto errorExit; } } } else if (rmInst->instType == Rm_instType_CLIENT_DELEGATE) { if (initCfg->instCfg.clientCfg.staticPolicy) { rmInst->u.cd.staticPolicy = initCfg->instCfg.cdCfg.staticPolicy; rmInst->u.cd.staticValidInstTree = rmPolicyCreateValidInstTree((Rm_Handle)rmInst, addLinux, result); if (*result == RM_OK) { *result = rmPolicyValidatePolicy((Rm_Handle)rmInst); } if (*result != RM_OK) { if (rmInst->u.cd.staticValidInstTree) { rmPolicyFreeValidInstTree((Rm_Handle)rmInst); } goto errorExit; } } } else if (rmInst->instType == Rm_instType_CLIENT) { if (initCfg->instCfg.cdCfg.staticPolicy) { rmInst->u.client.staticPolicy = initCfg->instCfg.clientCfg.staticPolicy; rmInst->u.client.staticValidInstTree = rmPolicyCreateValidInstTree((Rm_Handle)rmInst, addLinux, result); if (*result == RM_OK) { *result = rmPolicyValidatePolicy((Rm_Handle)rmInst); } if (*result != RM_OK) { if (rmInst->u.client.staticValidInstTree) { rmPolicyFreeValidInstTree((Rm_Handle)rmInst); } goto errorExit; } } } else if (rmInst->instType == Rm_instType_SHARED_CLIENT) { if (initCfg->instCfg.sharedClientCfg.sharedServerHandle) { rmInst->u.sharedClient.sharedServerHandle = initCfg->instCfg.sharedClientCfg.sharedServerHandle; /* Invalidate the Shared server instance structure on this core to get the latest * instance data. */ key = Rm_osalCsEnter(); Rm_osalBeginMemAccess((void *)rmInst->u.sharedClient.sharedServerHandle, sizeof(Rm_Inst)); sharedServerInst = rmInst->u.sharedClient.sharedServerHandle; if (sharedServerInst->instType != Rm_instType_SHARED_SERVER) { *result = RM_ERROR_INVALID_SHARED_SERVER_HANDLE; Rm_osalCsExit(key); goto errorExit; } Rm_osalCsExit(key); } else { *result = RM_ERROR_INVALID_SHARED_SERVER_HANDLE; goto errorExit; } } if (initCfg->instType == Rm_instType_SHARED_SERVER) { /* Writeback the instance for other cores */ Rm_osalEndMemAccess ((void *)rmInst, sizeof(Rm_Inst)); } else if (rmInst->instType != Rm_instType_SHARED_CLIENT) { /* Create the instance's task blocking mechanism */ rmInst->blockHandle = Rm_osalTaskBlockCreate(); } return ((Rm_Handle) rmInst); errorExit: if (rmInst) { Rm_osalFree((void *)rmInst, sizeof(Rm_Inst)); } return (NULL); } /* FUNCTION PURPOSE: Deletes an RM instance *********************************************************************** * DESCRIPTION: Frees all memory associated with an RM instance * as long as all transports have been unregistered * and the service handle has been closed */ int32_t Rm_delete(Rm_Handle rmHandle, int ignorePendingServices) { Rm_Inst *rmInst = (Rm_Inst *)rmHandle; void *key; key = Rm_osalCsEnter(); if (rmInst->instType == Rm_instType_SHARED_SERVER) { Rm_osalBeginMemAccess((void *)rmInst, sizeof(Rm_Inst)); } if (rmInst->serviceHandle) { return (RM_ERROR_CANT_DELETE_WITH_OPEN_SERV_HNDL); } else if (rmInst->transports) { return (RM_ERROR_CANT_DELETE_WITH_REGD_TRANSPORT); } else if (rmInst->transactionQueue && !ignorePendingServices) { return (RM_ERROR_CANT_DELETE_PENDING_TRANSACTIONS); } if ((rmInst->instType == Rm_instType_SERVER) || (rmInst->instType == Rm_instType_SHARED_SERVER)) { rmAllocatorDeleteResources(rmHandle); rmNameServerDelete(rmHandle); } if (rmInst->instType != Rm_instType_SHARED_CLIENT) { /* Delete valid instance tree */ rmPolicyFreeValidInstTree(rmHandle); /* Delete any transactions */ while(rmInst->transactionQueue) { rmTransactionQueueDelete(rmInst, rmInst->transactionQueue->localId); } if (rmInst->instType != Rm_instType_SHARED_SERVER) { /* Delete the instance's task blocking mechanism */ Rm_osalTaskBlockDelete(rmInst->blockHandle); } else { Rm_osalEndMemAccess((void *)rmInst, sizeof(Rm_Inst)); } } Rm_osalFree((void *)rmInst, sizeof(Rm_Inst)); Rm_osalCsExit(key); return (RM_OK); } /* FUNCTION PURPOSE: Returns RM version information *********************************************************************** */ uint32_t Rm_getVersion(void) { return RM_VERSION_ID; } /* FUNCTION PURPOSE: Returns RM version string *********************************************************************** */ const char* Rm_getVersionStr(void) { return rmVersionStr; }