5ac44d7a072e602c1a27555e3bd767c319c9062f
[processor-sdk/open-amp.git] / apps / rpc_demo / rpc_demod.c
1 /* This is a sample demonstration application that showcases usage of proxy from the remote core. 
2  This application is meant to run on the remote CPU running baremetal.
3  This applicationr can print to to master console and perform file I/O using proxy mechanism. */
5 #include <stdio.h>
6 #include <string.h>
7 #include <stdlib.h>
8 #include <fcntl.h>
9 #include <unistd.h>
10 #include"openamp/open_amp.h"
11 #include "openamp/rpmsg_retarget.h"
12 #include "metal/alloc.h"
13 #include "rsc_table.h"
14 #include "platform_info.h"
16 #define PROXY_ENDPOINT                  127
18 /* System call definitions */
19 #define OPEN_SYSCALL_ID         1
20 #define CLOSE_SYSCALL_ID        2
21 #define WRITE_SYSCALL_ID        3
22 #define READ_SYSCALL_ID         4
23 #define ACK_STATUS_ID           5
24 #define TERM_SYSCALL_ID         6
26 #define RPC_BUFF_SIZE 512
27 #define RPC_CHANNEL_READY_TO_CLOSE "rpc_channel_ready_to_close"
29 #define raw_printf(format, ...) printf(format, ##__VA_ARGS__)
30 #define LPRINTF(format, ...) raw_printf("Master> " format, ##__VA_ARGS__)
31 #define LPERROR(format, ...) LPRINTF("ERROR: " format, ##__VA_ARGS__)
33 struct _proxy_data {
34         int active;
35         int rpmsg_proxy_fd;
36         struct _sys_rpc *rpc;
37         struct _sys_rpc *rpc_response;
38         char *firmware_path;
39 };
41 /* Internal functions */
42 static void rpmsg_channel_created(struct rpmsg_channel *rp_chnl);
43 static void rpmsg_channel_deleted(struct rpmsg_channel *rp_chnl);
44 static void rpmsg_read_cb(struct rpmsg_channel *, void *, int, void *,
45                           unsigned long);
46 static void rpmsg_proxy_cb(struct rpmsg_channel *rp_chnl, void *data, int len,
47                           void *priv, unsigned long src);
49 /* Globals */
50 static struct rpmsg_channel *app_rp_chnl;
51 static struct rpmsg_endpoint *proxy_ept;
52 static struct remote_proc *proc = NULL;
53 static struct rsc_table_info rsc_info;
54 static struct _proxy_data *proxy;
55 static int err_cnt = 0;
57 extern const struct remote_resource_table resources;
58 extern struct rproc_info_plat_local proc_table;
60 /* External functions */
61 extern void init_system();
62 extern void cleanup_system();
64 #define REDEF_O_CREAT 100
65 #define REDEF_O_EXCL 200
66 #define REDEF_O_RDONLY 0
67 #define REDEF_O_WRONLY 1
68 #define REDEF_O_RDWR 2
69 #define REDEF_O_APPEND 2000
70 #define REDEF_O_ACCMODE 3
72 #define RPC_CHANNEL_READY_TO_CLOSE "rpc_channel_ready_to_close"
74 int handle_open(struct _sys_rpc *rpc)
75 {
76         int fd, ret;
78         /* Open remote fd */
79         fd = open(rpc->sys_call_args.data, rpc->sys_call_args.int_field1,
80                   rpc->sys_call_args.int_field2);
82         /* Construct rpc response */
83         proxy->rpc_response->id = OPEN_SYSCALL_ID;
84         proxy->rpc_response->sys_call_args.int_field1 = fd;
85         proxy->rpc_response->sys_call_args.int_field2 = 0;      /*not used */
86         proxy->rpc_response->sys_call_args.data_len = 0;        /*not used */
88         /* Transmit rpc response */
89         ret = rpmsg_sendto(app_rp_chnl, proxy->rpc_response,
90                         sizeof(struct _sys_rpc), PROXY_ENDPOINT);
92         return ret;
93 }
95 int handle_close(struct _sys_rpc *rpc)
96 {
97         int ret;
99         /* Close remote fd */
100         ret = close(rpc->sys_call_args.int_field1);
102         /* Construct rpc response */
103         proxy->rpc_response->id = CLOSE_SYSCALL_ID;
104         proxy->rpc_response->sys_call_args.int_field1 = ret;
105         proxy->rpc_response->sys_call_args.int_field2 = 0;      /*not used */
106         proxy->rpc_response->sys_call_args.data_len = 0;        /*not used */
108         /* Transmit rpc response */
109         ret = rpmsg_sendto(app_rp_chnl, proxy->rpc_response,
110                         sizeof(struct _sys_rpc), PROXY_ENDPOINT);
112         return ret;
115 int handle_read(struct _sys_rpc *rpc)
117         int bytes_read, payload_size;
118         char *buff;
119         int ret;
121         /* Allocate buffer for requested data size */
122         buff = malloc(rpc->sys_call_args.int_field2);
124         if (rpc->sys_call_args.int_field1 == 0)
125                 /* Perform read from fd for large size since this is a
126                    STD/I request */
127                 bytes_read = read(rpc->sys_call_args.int_field1, buff, 512);
128         else
129                 /* Perform read from fd */
130                 bytes_read = read(rpc->sys_call_args.int_field1, buff,
131                                   rpc->sys_call_args.int_field2);
133         /* Construct rpc response */
134         proxy->rpc_response->id = READ_SYSCALL_ID;
135         proxy->rpc_response->sys_call_args.int_field1 = bytes_read;
136         proxy->rpc_response->sys_call_args.int_field2 = 0;      /* not used */
137         proxy->rpc_response->sys_call_args.data_len = bytes_read;
138         if (bytes_read > 0)
139                 memcpy(proxy->rpc_response->sys_call_args.data, buff,
140                        bytes_read);
142         payload_size = sizeof(struct _sys_rpc) +
143             ((bytes_read > 0) ? bytes_read : 0);
145         /* Transmit rpc response */
146         ret = rpmsg_sendto(app_rp_chnl, proxy->rpc_response,
147                         payload_size, PROXY_ENDPOINT);
149         return ret;
152 int handle_write(struct _sys_rpc *rpc)
154         int bytes_written;
155         int ret;
157         /* Write to remote fd */
158         bytes_written = write(rpc->sys_call_args.int_field1,
159                               rpc->sys_call_args.data,
160                               rpc->sys_call_args.int_field2);
162         /* Construct rpc response */
163         proxy->rpc_response->id = WRITE_SYSCALL_ID;
164         proxy->rpc_response->sys_call_args.int_field1 = bytes_written;
165         proxy->rpc_response->sys_call_args.int_field2 = 0;      /*not used */
166         proxy->rpc_response->sys_call_args.data_len = 0;        /*not used */
168         /* Transmit rpc response */
169         ret = rpmsg_sendto(app_rp_chnl, proxy->rpc_response,
170                         sizeof(struct _sys_rpc), PROXY_ENDPOINT);
172         return ret;
175 int handle_rpc(struct _sys_rpc *rpc)
177         int retval;
178         char *data = (char *)rpc;
179         if (!strcmp(data, RPC_CHANNEL_READY_TO_CLOSE)) {
180                 proxy->active = 0;
181                 return 0;
182         }
184         /* Handle RPC */
185         switch ((int)(rpc->id)) {
186         case OPEN_SYSCALL_ID:
187                 {
188                         retval = handle_open(rpc);
189                         break;
190                 }
191         case CLOSE_SYSCALL_ID:
192                 {
193                         retval = handle_close(rpc);
194                         break;
195                 }
196         case READ_SYSCALL_ID:
197                 {
198                         retval = handle_read(rpc);
199                         break;
200                 }
201         case WRITE_SYSCALL_ID:
202                 {
203                         retval = handle_write(rpc);
204                         break;
205                 }
206         default:
207                 {
208                         LPERROR
209                             ("Invalid RPC sys call ID: %d:%d!\n",
210                              rpc->id, WRITE_SYSCALL_ID);
211                         retval = -1;
212                         break;
213                 }
214         }
216         return retval;
219 void terminate_rpc_app()
221         int msg = TERM_SYSCALL_ID;
222         LPRINTF("sending shutdown signal.\n");
223         rpmsg_sendto(app_rp_chnl, &msg, sizeof(msg), PROXY_ENDPOINT);
226 void exit_action_handler(int signum)
228         (void)signum;
229         proxy->active = 0;
232 void kill_action_handler(int signum)
234         (void)signum;
235         LPRINTF("RPC service killed !!\n");
237         /* Send shutdown signal to remote application */
238         if (app_rp_chnl)
239                 terminate_rpc_app();
241         /* wait for a while to let the remote finish cleanup */
242         sleep(1);
243         remoteproc_resource_deinit(proc);
245         /* Free up resources */
246         free(proxy->rpc);
247         free(proxy->rpc_response);
248         free(proxy);
250         cleanup_system();
253 /* Application entry point */
254 int main()
256         int status;
257         int ret = 0;
258         struct sigaction exit_action;
259         struct sigaction kill_action;
261         /* Initialize HW system components */
262         init_system();
264         /* Allocate memory for proxy data structure */
265         proxy = metal_allocate_memory(sizeof(struct _proxy_data));
266         if (!proxy) {
267                 LPERROR("Failed to allocate memory for proxy\n");
268                 return -1;
269         }
270         memset(proxy, 0, sizeof(struct _proxy_data));
271         proxy->active = 1;
272         /* Initialize signalling infrastructure */
273         memset(&exit_action, 0, sizeof(struct sigaction));
274         memset(&kill_action, 0, sizeof(struct sigaction));
275         exit_action.sa_handler = exit_action_handler;
276         kill_action.sa_handler = kill_action_handler;
277         sigaction(SIGTERM, &exit_action, NULL);
278         sigaction(SIGINT, &exit_action, NULL);
279         sigaction(SIGKILL, &kill_action, NULL);
280         sigaction(SIGHUP, &kill_action, NULL);
282         /* Allocate memory for rpc payloads */
283         proxy->rpc = metal_allocate_memory(RPC_BUFF_SIZE);
284         proxy->rpc_response = metal_allocate_memory(RPC_BUFF_SIZE);
285         if (!proxy->rpc || !proxy->rpc_response) {
286                 LPERROR("Failed to allocate memory for proxy data\n");
287                 ret = -1;
288                 goto error1;
289         }
291         rsc_info.rsc_tab = (struct resource_table *)&resources;
292         rsc_info.size = sizeof(resources);
294         /* Initialize RPMSG framework */
295         status =
296             remoteproc_resource_init(&rsc_info, &proc_table,
297                                      rpmsg_channel_created,
298                                      rpmsg_channel_deleted, rpmsg_read_cb,
299                                      &proc, 1);
301         if (status) {
302                 LPERROR("Failed  to initialize remoteproc resource.\n");
303                 ret = -1;
304                 goto error1;
305         }
307         LPRINTF("Remote proc resource initialized.\n");
308         while (!app_rp_chnl) {
309                 hil_poll(proc->proc, 0);
310         }
312         LPRINTF("RPMSG channel has created.\n");
313         while(proxy->active && app_rp_chnl && !err_cnt) {
314                  hil_poll(proc->proc, 0);
315         }
317         if (err_cnt) {
318                 LPERROR("Got error!\n");
319                 ret = -1;
320         }
321         LPRINTF("\nRPC service exiting !!\n");
323         /* Send shutdown signal to remote application */
324         if (app_rp_chnl)
325                 terminate_rpc_app();
327         /* Need to wait here for sometime to allow remote application to
328            complete its unintialization */
329         sleep(1);
331         remoteproc_resource_deinit(proc);
333 error1:
334         /* Free up resources */
335         if (proxy->rpc)
336                 metal_free_memory(proxy->rpc);
337         if (proxy->rpc_response)
338                 metal_free_memory(proxy->rpc_response);
339         if (proxy)
340                 metal_free_memory(proxy);
342         cleanup_system();
344         return ret;
347 static void rpmsg_channel_created(struct rpmsg_channel *rp_chnl)
349         proxy_ept = rpmsg_create_ept(rp_chnl, rpmsg_proxy_cb, RPMSG_NULL,
350                                   PROXY_ENDPOINT);
351         app_rp_chnl = rp_chnl;
354 static void rpmsg_channel_deleted(struct rpmsg_channel *rp_chnl)
356         (void)rp_chnl;
357         rpmsg_destroy_ept(proxy_ept);
358         proxy_ept = NULL;
359         app_rp_chnl = NULL;
362 static void rpmsg_read_cb(struct rpmsg_channel *rp_chnl, void *data, int len,
363                           void *priv, unsigned long src)
365         (void)rp_chnl;
366         (void)data;
367         (void)len;
368         (void)priv;
369         (void)src;
372 static void rpmsg_proxy_cb(struct rpmsg_channel *rp_chnl, void *data, int len,
373                           void *priv, unsigned long src)
375         (void)rp_chnl;
376         (void)priv;
377         (void)src;
379         if (len < (int)sizeof(struct _sys_rpc)) {
380                 LPERROR("Received data is less than the rpc structure: %d\n",
381                         len);
382                 err_cnt++;
383         }
385         /* In case the shared memory is device memory
386          * E.g. For now, we only use UIO device memory in Linux.
387          */
388         metal_memcpy_io(proxy->rpc, data, len);
389         if (handle_rpc(proxy->rpc)) {
390                 LPRINTF("\nHandling remote procedure call errors:\n");
391                 raw_printf("rpc id %d\n", proxy->rpc->id);
392                 raw_printf("rpc int field1 %d\n",
393                        proxy->rpc->sys_call_args.int_field1);
394                 raw_printf("\nrpc int field2 %d\n",
395                        proxy->rpc->sys_call_args.int_field2);
396                 err_cnt++;
397         }