Update demo apps to use new HIL proc APIs
[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"
15 #define PROXY_ENDPOINT                  127
17 /* System call definitions */
18 #define OPEN_SYSCALL_ID         1
19 #define CLOSE_SYSCALL_ID        2
20 #define WRITE_SYSCALL_ID        3
21 #define READ_SYSCALL_ID         4
22 #define ACK_STATUS_ID           5
23 #define TERM_SYSCALL_ID         6
25 #define RPC_BUFF_SIZE 512
26 #define RPC_CHANNEL_READY_TO_CLOSE "rpc_channel_ready_to_close"
28 #define raw_printf(format, ...) printf(format, ##__VA_ARGS__)
29 #define LPRINTF(format, ...) raw_printf("Master> " format, ##__VA_ARGS__)
30 #define LPERROR(format, ...) LPRINTF("ERROR: " format, ##__VA_ARGS__)
32 struct _proxy_data {
33         int active;
34         int rpmsg_proxy_fd;
35         struct _sys_rpc *rpc;
36         struct _sys_rpc *rpc_response;
37         char *firmware_path;
38 };
40 /* Internal functions */
41 static void rpmsg_channel_created(struct rpmsg_channel *rp_chnl);
42 static void rpmsg_channel_deleted(struct rpmsg_channel *rp_chnl);
43 static void rpmsg_read_cb(struct rpmsg_channel *, void *, int, void *,
44                           unsigned long);
45 static void rpmsg_proxy_cb(struct rpmsg_channel *rp_chnl, void *data, int len,
46                           void *priv, unsigned long src);
48 /* Globals */
49 static struct rpmsg_channel *app_rp_chnl;
50 static struct rpmsg_endpoint *proxy_ept;
51 static struct remote_proc *proc = NULL;
52 static struct rsc_table_info rsc_info;
53 static struct _proxy_data *proxy;
54 static int err_cnt = 0;
56 extern const struct remote_resource_table resources;
58 /* External functions */
59 extern void init_system();
60 extern void cleanup_system();
61 extern struct hil_proc *platform_create_proc(int proc_index);
63 #define REDEF_O_CREAT 100
64 #define REDEF_O_EXCL 200
65 #define REDEF_O_RDONLY 0
66 #define REDEF_O_WRONLY 1
67 #define REDEF_O_RDWR 2
68 #define REDEF_O_APPEND 2000
69 #define REDEF_O_ACCMODE 3
71 #define RPC_CHANNEL_READY_TO_CLOSE "rpc_channel_ready_to_close"
73 int handle_open(struct _sys_rpc *rpc)
74 {
75         int fd, ret;
77         /* Open remote fd */
78         fd = open(rpc->sys_call_args.data, rpc->sys_call_args.int_field1,
79                   rpc->sys_call_args.int_field2);
81         /* Construct rpc response */
82         proxy->rpc_response->id = OPEN_SYSCALL_ID;
83         proxy->rpc_response->sys_call_args.int_field1 = fd;
84         proxy->rpc_response->sys_call_args.int_field2 = 0;      /*not used */
85         proxy->rpc_response->sys_call_args.data_len = 0;        /*not used */
87         /* Transmit rpc response */
88         ret = rpmsg_sendto(app_rp_chnl, proxy->rpc_response,
89                         sizeof(struct _sys_rpc), PROXY_ENDPOINT);
91         return ret;
92 }
94 int handle_close(struct _sys_rpc *rpc)
95 {
96         int ret;
98         /* Close remote fd */
99         ret = close(rpc->sys_call_args.int_field1);
101         /* Construct rpc response */
102         proxy->rpc_response->id = CLOSE_SYSCALL_ID;
103         proxy->rpc_response->sys_call_args.int_field1 = ret;
104         proxy->rpc_response->sys_call_args.int_field2 = 0;      /*not used */
105         proxy->rpc_response->sys_call_args.data_len = 0;        /*not used */
107         /* Transmit rpc response */
108         ret = rpmsg_sendto(app_rp_chnl, proxy->rpc_response,
109                         sizeof(struct _sys_rpc), PROXY_ENDPOINT);
111         return ret;
114 int handle_read(struct _sys_rpc *rpc)
116         int bytes_read, payload_size;
117         char *buff;
118         int ret;
120         /* Allocate buffer for requested data size */
121         buff = malloc(rpc->sys_call_args.int_field2);
123         if (rpc->sys_call_args.int_field1 == 0)
124                 /* Perform read from fd for large size since this is a
125                    STD/I request */
126                 bytes_read = read(rpc->sys_call_args.int_field1, buff, 512);
127         else
128                 /* Perform read from fd */
129                 bytes_read = read(rpc->sys_call_args.int_field1, buff,
130                                   rpc->sys_call_args.int_field2);
132         /* Construct rpc response */
133         proxy->rpc_response->id = READ_SYSCALL_ID;
134         proxy->rpc_response->sys_call_args.int_field1 = bytes_read;
135         proxy->rpc_response->sys_call_args.int_field2 = 0;      /* not used */
136         proxy->rpc_response->sys_call_args.data_len = bytes_read;
137         if (bytes_read > 0)
138                 memcpy(proxy->rpc_response->sys_call_args.data, buff,
139                        bytes_read);
141         payload_size = sizeof(struct _sys_rpc) +
142             ((bytes_read > 0) ? bytes_read : 0);
144         /* Transmit rpc response */
145         ret = rpmsg_sendto(app_rp_chnl, proxy->rpc_response,
146                         payload_size, PROXY_ENDPOINT);
148         return ret;
151 int handle_write(struct _sys_rpc *rpc)
153         int bytes_written;
154         int ret;
156         /* Write to remote fd */
157         bytes_written = write(rpc->sys_call_args.int_field1,
158                               rpc->sys_call_args.data,
159                               rpc->sys_call_args.int_field2);
161         /* Construct rpc response */
162         proxy->rpc_response->id = WRITE_SYSCALL_ID;
163         proxy->rpc_response->sys_call_args.int_field1 = bytes_written;
164         proxy->rpc_response->sys_call_args.int_field2 = 0;      /*not used */
165         proxy->rpc_response->sys_call_args.data_len = 0;        /*not used */
167         /* Transmit rpc response */
168         ret = rpmsg_sendto(app_rp_chnl, proxy->rpc_response,
169                         sizeof(struct _sys_rpc), PROXY_ENDPOINT);
171         return ret;
174 int handle_rpc(struct _sys_rpc *rpc)
176         int retval;
177         char *data = (char *)rpc;
178         if (!strcmp(data, RPC_CHANNEL_READY_TO_CLOSE)) {
179                 proxy->active = 0;
180                 return 0;
181         }
183         /* Handle RPC */
184         switch ((int)(rpc->id)) {
185         case OPEN_SYSCALL_ID:
186                 {
187                         retval = handle_open(rpc);
188                         break;
189                 }
190         case CLOSE_SYSCALL_ID:
191                 {
192                         retval = handle_close(rpc);
193                         break;
194                 }
195         case READ_SYSCALL_ID:
196                 {
197                         retval = handle_read(rpc);
198                         break;
199                 }
200         case WRITE_SYSCALL_ID:
201                 {
202                         retval = handle_write(rpc);
203                         break;
204                 }
205         default:
206                 {
207                         LPERROR
208                             ("Invalid RPC sys call ID: %d:%d!\n",
209                              rpc->id, WRITE_SYSCALL_ID);
210                         retval = -1;
211                         break;
212                 }
213         }
215         return retval;
218 void terminate_rpc_app()
220         int msg = TERM_SYSCALL_ID;
221         LPRINTF("sending shutdown signal.\n");
222         rpmsg_sendto(app_rp_chnl, &msg, sizeof(msg), PROXY_ENDPOINT);
225 void exit_action_handler(int signum)
227         (void)signum;
228         proxy->active = 0;
231 void kill_action_handler(int signum)
233         (void)signum;
234         LPRINTF("RPC service killed !!\n");
236         /* Send shutdown signal to remote application */
237         if (app_rp_chnl)
238                 terminate_rpc_app();
240         /* wait for a while to let the remote finish cleanup */
241         sleep(1);
242         remoteproc_resource_deinit(proc);
244         /* Free up resources */
245         free(proxy->rpc);
246         free(proxy->rpc_response);
247         free(proxy);
249         cleanup_system();
252 /* Application entry point */
253 int main()
255         int status;
256         int ret = 0;
257         struct sigaction exit_action;
258         struct sigaction kill_action;
259         struct hil_proc *hproc;
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         /* Create HIL proc */
295         hproc = platform_create_proc(0);
296         if (!hproc) {
297                 LPERROR("Failed to create hil proc.\n");
298                 return -1;
299         }
301         /* Initialize RPMSG framework */
302         status =
303             remoteproc_resource_init(&rsc_info, hproc,
304                                      rpmsg_channel_created,
305                                      rpmsg_channel_deleted, rpmsg_read_cb,
306                                      &proc, 1);
308         if (status) {
309                 LPERROR("Failed  to initialize remoteproc resource.\n");
310                 ret = -1;
311                 goto error1;
312         }
314         LPRINTF("Remote proc resource initialized.\n");
315         while (!app_rp_chnl) {
316                 hil_poll(proc->proc, 0);
317         }
319         LPRINTF("RPMSG channel has created.\n");
320         while(proxy->active && app_rp_chnl && !err_cnt) {
321                  hil_poll(proc->proc, 0);
322         }
324         if (err_cnt) {
325                 LPERROR("Got error!\n");
326                 ret = -1;
327         }
328         LPRINTF("\nRPC service exiting !!\n");
330         /* Send shutdown signal to remote application */
331         if (app_rp_chnl)
332                 terminate_rpc_app();
334         /* Need to wait here for sometime to allow remote application to
335            complete its unintialization */
336         sleep(1);
338         remoteproc_resource_deinit(proc);
340 error1:
341         /* Free up resources */
342         if (proxy->rpc)
343                 metal_free_memory(proxy->rpc);
344         if (proxy->rpc_response)
345                 metal_free_memory(proxy->rpc_response);
346         if (proxy)
347                 metal_free_memory(proxy);
349         cleanup_system();
351         return ret;
354 static void rpmsg_channel_created(struct rpmsg_channel *rp_chnl)
356         proxy_ept = rpmsg_create_ept(rp_chnl, rpmsg_proxy_cb, RPMSG_NULL,
357                                   PROXY_ENDPOINT);
358         app_rp_chnl = rp_chnl;
361 static void rpmsg_channel_deleted(struct rpmsg_channel *rp_chnl)
363         (void)rp_chnl;
364         rpmsg_destroy_ept(proxy_ept);
365         proxy_ept = NULL;
366         app_rp_chnl = NULL;
369 static void rpmsg_read_cb(struct rpmsg_channel *rp_chnl, void *data, int len,
370                           void *priv, unsigned long src)
372         (void)rp_chnl;
373         (void)data;
374         (void)len;
375         (void)priv;
376         (void)src;
379 static void rpmsg_proxy_cb(struct rpmsg_channel *rp_chnl, void *data, int len,
380                           void *priv, unsigned long src)
382         (void)rp_chnl;
383         (void)priv;
384         (void)src;
386         if (len < (int)sizeof(struct _sys_rpc)) {
387                 LPERROR("Received data is less than the rpc structure: %d\n",
388                         len);
389                 err_cnt++;
390         }
392         /* In case the shared memory is device memory
393          * E.g. For now, we only use UIO device memory in Linux.
394          */
395         metal_memcpy_io(proxy->rpc, data, len);
396         if (handle_rpc(proxy->rpc)) {
397                 LPRINTF("\nHandling remote procedure call errors:\n");
398                 raw_printf("rpc id %d\n", proxy->rpc->id);
399                 raw_printf("rpc int field1 %d\n",
400                        proxy->rpc->sys_call_args.int_field1);
401                 raw_printf("\nrpc int field2 %d\n",
402                        proxy->rpc->sys_call_args.int_field2);
403                 err_cnt++;
404         }