TransportRpmsg: Add NULL check to avoid NULL pointer access
[ipc/ipcdev.git] / packages / ti / ipc / transports / TransportRpmsg.c
1 /*
2  * Copyright (c) 2012-2019, Texas Instruments Incorporated
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * *  Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * *  Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * *  Neither the name of Texas Instruments Incorporated nor the names of
17  *    its contributors may be used to endorse or promote products derived
18  *    from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 /*
33  *  ======== TransportRpmsg.c ========
34  */
36 #include <string.h>
38 #include <xdc/std.h>
40 #include <xdc/runtime/System.h>
41 #include <xdc/runtime/Assert.h>
42 #include <xdc/runtime/Error.h>
43 #include <xdc/runtime/Memory.h>
44 #include <xdc/runtime/Main.h>
45 #include <xdc/runtime/Registry.h>
46 #include <xdc/runtime/Log.h>
47 #include <xdc/runtime/Diags.h>
50 #include <ti/sdo/utils/_MultiProc.h>
51 #include <ti/sdo/ipc/_MessageQ.h>
53 #include <ti/ipc/rpmsg/virtio_ring.h>
54 #include <ti/ipc/rpmsg/_VirtQueue.h>
55 #include <ti/ipc/rpmsg/Rpmsg.h>
56 #include <ti/ipc/rpmsg/NameMap.h>
58 #include <ti/ipc/rpmsg/_RPMessage.h>
59 #include <ti/ipc/rpmsg/RPMessage.h>
61 #include <ti/ipc/namesrv/_NameServerRemoteRpmsg.h>
63 #include "_TransportRpmsg.h"
64 #include "package/internal/TransportRpmsg.xdc.h"
66 /* Maximum RPMSG payload: */
67 #define MAX_PAYLOAD (RPMSG_BUF_SIZE - sizeof(Rpmsg_Header))
69 /* Addresses below this are assumed to be bound to MessageQ objects: */
70 #define RPMSG_RESERVED_ADDRESSES     (1024)
72 /* Name of the rpmsg socket on host: */
73 #define RPMSG_SOCKET_NAME  "rpmsg-proto"
75 static Void transportCallbackFxn(RPMessage_Handle msgq, UArg arg, Ptr data,
76                                       UInt16 dataLen, UInt32 srcAddr);
78 /*
79  *************************************************************************
80  *                       Instance functions
81  *************************************************************************
82  */
84 /*
85  *  ======== TransportRpmsg_Instance_init ========
86  *
87  */
88 #define FXNN "TransportRpmsg_Instance_init"
89 Int TransportRpmsg_Instance_init(TransportRpmsg_Object *obj,
90         UInt16 remoteProcId, const TransportRpmsg_Params *params,
91         Error_Block *eb)
92 {
93     Bool        flag = FALSE;
94     UInt32      myEndpoint = 0;
96     Log_print1(Diags_INFO, FXNN": remoteProc: %d\n", remoteProcId);
98     /* This MessageQ Transport over RPMSG only talks to the "HOST" for now: */
99     Assert_isTrue(remoteProcId == MultiProc_getId("HOST"), NULL);
100     RPMessage_init(remoteProcId);
102     /* set object fields */
103     obj->priority     = params->priority;
104     obj->remoteProcId = remoteProcId;
106     /* Announce our "MessageQ" service to the HOST: */
107 #ifdef RPMSG_NS_2_0
108     NameMap_register(RPMSG_SOCKET_NAME, RPMSG_SOCKET_NAME, RPMSG_MESSAGEQ_PORT);
109 #else
110     NameMap_register(RPMSG_SOCKET_NAME, RPMSG_MESSAGEQ_PORT);
111 #endif
113     /* Associate incomming messages with this transport's callback fxn: */
114     obj->msgqHandle = RPMessage_create(RPMSG_MESSAGEQ_PORT,
115                                           transportCallbackFxn,
116                                           (UArg)obj,
117                                           &myEndpoint);
119     /*
120      * TBD: The following should be set via a ns_announcement from Linux side.
121      * Setting this now will cause NameServer requests from BIOS side to
122      * timeout (benignly), if the app calls MessageQ_open() in a loop.
123      * Ideally, a NameMap module needs to allow registration for announcements.
124      */
125     NameServerRemote_SetNameServerPort(NAME_SERVER_RPMSG_ADDR);
127     if (obj->msgqHandle) {
128         /* Register the transport with MessageQ */
129         flag = ti_sdo_ipc_MessageQ_registerTransport(
130             TransportRpmsg_Handle_upCast(obj), remoteProcId, params->priority);
131     }
133     if (flag == FALSE) {
134         return (2);
135     }
137     return (0);
139 #undef FXNN
141 /*
142  *  ======== TransportRpmsg_Instance_finalize ========
143  */
144 #define FXNN "TransportRpmsg_Instance_finalize"
145 Void TransportRpmsg_Instance_finalize(TransportRpmsg_Object *obj, Int status)
147     Log_print0(Diags_ENTRY, "--> "FXNN);
149     /* Announce our "MessageQ" service is going away: */
150 #ifdef RPMSG_NS_2_0
151     NameMap_unregister(RPMSG_SOCKET_NAME, RPMSG_SOCKET_NAME,
152             RPMSG_MESSAGEQ_PORT);
153 #else
154     NameMap_unregister(RPMSG_SOCKET_NAME, RPMSG_MESSAGEQ_PORT);
155 #endif
157     switch(status) {
158         case 0: /* MessageQ_registerTransport succeeded */
159             ti_sdo_ipc_MessageQ_unregisterTransport(obj->remoteProcId,
160                 obj->priority);
161             /* fall thru OK */
162         case 1: /* NOT USED: Notify_registerEventSingle failed */
163         case 2: /* MessageQ_registerTransport failed */
164             break;
165     }
167     RPMessage_finalize();
169 #undef FXNN
172 /*
173  *  ======== TransportRpmsg_put ========
174  *
175  *  Notes: In keeping with the semantics of IMessageQTransport_put(), we
176  *  simply return FALSE if the remote proc has made no buffers available in the
177  *  vring.
178  *  Otherwise, we could block here, waiting for the remote proc to add a buffer.
179  *  This implies that the remote proc must always have buffers available in the
180  *  vring in order for this side to send without failing!
181  *
182  *  Also, this is a copy-transport, to match the Linux side rpmsg.
183  */
184 #define FXNN "TransportRpmsg_put"
185 Bool TransportRpmsg_put(TransportRpmsg_Object *obj, Ptr msg)
187     Int          status;
188     UInt         msgSize;
189     UInt16       dstAddr;
191     /* Send to remote processor: */
192     /* Assert msg->msgSize <= vring's max fixed buffer size */
193     msgSize = MessageQ_getMsgSize(msg);
194     Assert_isTrue(msgSize <= MAX_PAYLOAD, NULL);
195     dstAddr  = (((MessageQ_Msg)msg)->dstId & 0x0000FFFF);
197     Log_print3(Diags_INFO, FXNN": sending msg from: %d, to: %d, dataLen: %d",
198                   (IArg)RPMSG_MESSAGEQ_PORT, (IArg)dstAddr, (IArg)msgSize);
199     status = RPMessage_send(obj->remoteProcId, dstAddr, RPMSG_MESSAGEQ_PORT,
200                       msg, msgSize);
202     /* free the app's message */
203     if (((MessageQ_Msg)msg)->heapId != ti_sdo_ipc_MessageQ_STATICMSG) {
204        MessageQ_free(msg);
205     }
207     return (status == RPMessage_S_SUCCESS? TRUE: FALSE);
209 #undef FXNN
211 /*
212  *  ======== TransportRpmsg_control ========
213  */
214 Bool TransportRpmsg_control(TransportRpmsg_Object *obj, UInt cmd,
215     UArg cmdArg)
217     return (FALSE);
220 /*
221  *  ======== TransportRpmsg_getStatus ========
222  */
223 Int TransportRpmsg_getStatus(TransportRpmsg_Object *obj)
225     return (0);
228 /*
229  *************************************************************************
230  *                       Module functions
231  *************************************************************************
232  */
234 /*
235  *  ======== transportCallbackFxn ========
236  *
237  */
238 #define FXNN "transportCallbackFxn"
239 static Void transportCallbackFxn(RPMessage_Handle msgq, UArg arg, Ptr data,
240                                       UInt16 dataLen, UInt32 srcAddr)
242     UInt32            queueId;
243     MessageQ_Msg      msg;
244     MessageQ_Msg      buf = NULL;
245     UInt              msgSize;
246     NameServerRemote_Msg * nsrMsg;  /* Name Server Message */
248     Log_print0(Diags_ENTRY, "--> "FXNN);
250     Log_print3(Diags_INFO, FXNN": Received data: 0x%x from: %d, dataLen: %d",
251                   (IArg)data, (IArg)srcAddr, (IArg)dataLen);
252 #if 0
253 /* TBD: This logic needs to be put in a callback from the name service endpt: */
254     {
255         Int               nsPort = NAME_SERVER_PORT_INVALID;
257         /* See if this is an rpmsg ns announcment... : */
258         if (rpMsg->dstAddr != RPMSG_MESSAGEQ_PORT) {
259             if (rpMsg->dstAddr == RPMSG_NAMESERVICE_PORT) {
260                 nsMsg = (Rpmsg_NsMsg *)rpMsg->payload;
261                 Log_print3(Diags_USER1, FXNN": ns announcement "
262                   "from %d: %s, flag: %s\n",
263                   nsMsg->addr, (IArg)nsMsg->name,
264                   (IArg)(nsMsg->flags == RPMSG_NS_CREATE? "create":"destroy"));
265                 /* ... and if it is from our rpmsg-proto socket, save
266                  * the rpmsg src address as the NameServer reply address:
267                  */
268                 if (!strcmp(nsMsg->name, RPMSG_SOCKET_NAME) &&
269                     rpMsg->srcAddr == NAME_SERVER_RPMSG_ADDR) {
270                     if (nsMsg->flags == RPMSG_NS_CREATE) {
271                         nsPort = NAME_SERVER_RPMSG_ADDR;
272                     }
273                     else if (nsMsg->flags  == RPMSG_NS_DESTROY) {
274                         nsPort = NAME_SERVER_PORT_INVALID;
275                     }
276                     NameServerRemote_SetNameServerPort(nsPort);
277                 }
278             }
279             goto skip;
280         }
281     }
282 #endif
283     if(srcAddr >= RPMSG_RESERVED_ADDRESSES) {
284         /*
285          * This could either be a NameServer request or a MessageQ.
286          * Check the NameServerRemote_Msg reserved field to distinguish.
287          */
288         nsrMsg = (NameServerRemote_Msg *)data;
289         if (nsrMsg->reserved == NAMESERVER_MSG_TOKEN) {
290             /* Process the NameServer request/reply message: */
291             NameServerRemote_processMessage(nsrMsg);
292             goto exit;
293         }
294     }
296     /* Convert Rpmsg payload into a MessageQ_Msg: */
297     msg = (MessageQ_Msg)data;
299     Log_print4(Diags_INFO, FXNN": \n\tmsg->heapId: %d, "
300                "msg->msgSize: %d, msg->dstId: %d, msg->msgId: %d\n",
301                msg->heapId, msg->msgSize, msg->dstId, msg->msgId);
303     /* Alloc a message from msg->heapId to copy the msg */
304     msgSize = MessageQ_getMsgSize(msg);
305     buf = MessageQ_alloc(msg->heapId, msgSize);
307     /* Make sure buf is not NULL */
308     Assert_isTrue(buf != NULL, NULL);
309     if (buf == NULL) {
310         Log_print0(Diags_INFO, FXNN" MessageQ_alloc failed \n");
311         goto exit;
312     }
314     /* copy the message to the buffer allocated. */
315     memcpy((Ptr)buf, (Ptr)msg, msgSize);
317     /*
318      * If the message received was statically allocated, reset the
319      * heapId, so the app can free it.
320      */
321     if (msg->heapId == ti_sdo_ipc_MessageQ_STATICMSG)  {
322         msg->heapId = 0;  /* for a copy transport, heap id is 0. */
323     }
325     /* get the queue id */
326     queueId = MessageQ_getDstQueue(msg);
328     /* Pass to desitination queue: */
329     MessageQ_put(queueId, buf);
331 exit:
332     Log_print0(Diags_EXIT, "<-- "FXNN);
335 /*
336  *  ======== TransportRpmsg_setErrFxn ========
337  */
338 Void TransportRpmsg_setErrFxn(TransportRpmsg_ErrFxn errFxn)
340     /* Ignore the errFxn */