1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <time.h>
5 #include <fcntl.h>
6 #include <string.h>
7 #include <sys/ioctl.h>
8 #include <signal.h>
9 #include <unistd.h>
10 #include "proxy_app.h"
12 #define RPC_BUFF_SIZE 512
13 #define RPC_CHANNEL_READY_TO_CLOSE "rpc_channel_ready_to_close"
15 struct _proxy_data {
16 int active;
17 int rpmsg_proxy_fd;
18 struct _sys_rpc *rpc;
19 struct _sys_rpc *rpc_response;
20 char *firmware_path;
21 };
23 static struct _proxy_data *proxy;
24 char fw_dst_path[] = "/lib/firmware/r5_image_rpc_demo";
26 char *rproc_name = 0;
28 int handle_open(struct _sys_rpc *rpc)
29 {
30 int fd, bytes_written;
32 /* Open remote fd */
33 fd = open(rpc->sys_call_args.data, rpc->sys_call_args.int_field1,
34 rpc->sys_call_args.int_field2);
36 /* Construct rpc response */
37 proxy->rpc_response->id = OPEN_SYSCALL_ID;
38 proxy->rpc_response->sys_call_args.int_field1 = fd;
39 proxy->rpc_response->sys_call_args.int_field2 = 0; /*not used */
40 proxy->rpc_response->sys_call_args.data_len = 0; /*not used */
42 /* Transmit rpc response */
43 bytes_written = write(proxy->rpmsg_proxy_fd, proxy->rpc_response,
44 sizeof(struct _sys_rpc));
46 return (bytes_written != sizeof(struct _sys_rpc)) ? -1 : 0;
47 }
49 int handle_close(struct _sys_rpc *rpc)
50 {
51 int retval, bytes_written;
53 /* Close remote fd */
54 retval = close(rpc->sys_call_args.int_field1);
56 /* Construct rpc response */
57 proxy->rpc_response->id = CLOSE_SYSCALL_ID;
58 proxy->rpc_response->sys_call_args.int_field1 = retval;
59 proxy->rpc_response->sys_call_args.int_field2 = 0; /*not used */
60 proxy->rpc_response->sys_call_args.data_len = 0; /*not used */
62 /* Transmit rpc response */
63 bytes_written = write(proxy->rpmsg_proxy_fd, proxy->rpc_response,
64 sizeof(struct _sys_rpc));
66 return (bytes_written != sizeof(struct _sys_rpc)) ? -1 : 0;
67 }
69 int handle_read(struct _sys_rpc *rpc)
70 {
71 int bytes_read, bytes_written, payload_size;
72 char *buff;
74 /* Allocate buffer for requested data size */
75 buff = malloc(rpc->sys_call_args.int_field2);
77 if (rpc->sys_call_args.int_field1 == 0)
78 /* Perform read from fd for large size since this is a
79 STD/I request */
80 bytes_read = read(rpc->sys_call_args.int_field1, buff, 512);
81 else
82 /* Perform read from fd */
83 bytes_read = read(rpc->sys_call_args.int_field1, buff,
84 rpc->sys_call_args.int_field2);
86 /* Construct rpc response */
87 proxy->rpc_response->id = READ_SYSCALL_ID;
88 proxy->rpc_response->sys_call_args.int_field1 = bytes_read;
89 proxy->rpc_response->sys_call_args.int_field2 = 0; /* not used */
90 proxy->rpc_response->sys_call_args.data_len = bytes_read;
91 if (bytes_read > 0)
92 memcpy(proxy->rpc_response->sys_call_args.data, buff,
93 bytes_read);
95 payload_size = sizeof(struct _sys_rpc) +
96 ((bytes_read > 0) ? bytes_read : 0);
98 /* Transmit rpc response */
99 bytes_written = write(proxy->rpmsg_proxy_fd, proxy->rpc_response,
100 payload_size);
102 return (bytes_written != payload_size) ? -1 : 0;
103 }
105 int handle_write(struct _sys_rpc *rpc)
106 {
107 int bytes_written;
109 /* Write to remote fd */
110 bytes_written = write(rpc->sys_call_args.int_field1,
111 rpc->sys_call_args.data,
112 rpc->sys_call_args.int_field2);
114 /* Construct rpc response */
115 proxy->rpc_response->id = WRITE_SYSCALL_ID;
116 proxy->rpc_response->sys_call_args.int_field1 = bytes_written;
117 proxy->rpc_response->sys_call_args.int_field2 = 0; /*not used */
118 proxy->rpc_response->sys_call_args.data_len = 0; /*not used */
120 /* Transmit rpc response */
121 bytes_written = write(proxy->rpmsg_proxy_fd, proxy->rpc_response,
122 sizeof(struct _sys_rpc));
124 return (bytes_written != sizeof(struct _sys_rpc)) ? -1 : 0;
125 }
127 int handle_rpc(struct _sys_rpc *rpc)
128 {
129 int retval;
130 char *data = (char *)rpc;
131 if (!strcmp(data, RPC_CHANNEL_READY_TO_CLOSE)) {
132 proxy->active = 0;
133 return 0;
134 }
136 /* Handle RPC */
137 switch ((int)(rpc->id)) {
138 case OPEN_SYSCALL_ID:
139 {
140 retval = handle_open(rpc);
141 break;
142 }
143 case CLOSE_SYSCALL_ID:
144 {
145 retval = handle_close(rpc);
146 break;
147 }
148 case READ_SYSCALL_ID:
149 {
150 retval = handle_read(rpc);
151 break;
152 }
153 case WRITE_SYSCALL_ID:
154 {
155 retval = handle_write(rpc);
156 break;
157 }
158 default:
159 {
160 printf
161 ("\r\nMaster>Err:Invalid RPC sys call ID: %d:%d! \r\n",
162 rpc->id, WRITE_SYSCALL_ID);
163 retval = -1;
164 break;
165 }
166 }
168 return retval;
169 }
171 int terminate_rpc_app()
172 {
173 int bytes_written;
174 int msg = TERM_SYSCALL_ID;
175 printf("Master> sending shutdown signal.\n");
176 bytes_written = write(proxy->rpmsg_proxy_fd, &msg, sizeof(int));
177 return bytes_written;
178 }
180 void exit_action_handler(int signum)
181 {
182 proxy->active = 0;
183 }
185 void unload_drivers()
186 {
187 char sys_cmd[256];
189 system("modprobe -r rpmsg_proxy_dev_driver");
190 system("modprobe -r virtio_rpmsg_bus");
191 if (rproc_name) {
192 sprintf(sys_cmd, "modprobe -r %s", rproc_name);
193 system(sys_cmd);
194 }
195 system("modprobe -r remoteproc");
196 system("modprobe -r virtio_ring");
197 system("modprobe -r virtio");
198 }
200 void kill_action_handler(int signum)
201 {
202 printf("\r\nMaster>RPC service killed !!\r\n");
204 /* Send shutdown signal to remote application */
205 terminate_rpc_app();
207 /* wait for a while to let the remote finish cleanup */
208 sleep(1);
209 /* Close proxy rpmsg device */
210 close(proxy->rpmsg_proxy_fd);
212 /* Free up resources */
213 free(proxy->rpc);
214 free(proxy->rpc_response);
215 free(proxy);
217 /* Unload drivers */
218 unload_drivers();
219 }
221 void display_help_msg()
222 {
223 printf("\r\nLinux proxy application.\r\n");
224 printf("-r Displays proxy application version.\n");
225 printf("-f Accepts path of firmware to load on remote core.\n");
226 printf("-h Displays this help message.\n");
227 }
229 int main(int argc, char *argv[])
230 {
231 struct sigaction exit_action;
232 struct sigaction kill_action;
233 unsigned int bytes_rcvd;
234 int i = 0;
235 int ret = 0;
236 char *firmware_path = 0;
237 char sys_cmd[512];
239 /* Initialize signalling infrastructure */
240 memset(&exit_action, 0, sizeof(struct sigaction));
241 memset(&kill_action, 0, sizeof(struct sigaction));
242 exit_action.sa_handler = exit_action_handler;
243 kill_action.sa_handler = kill_action_handler;
244 sigaction(SIGTERM, &exit_action, NULL);
245 sigaction(SIGINT, &exit_action, NULL);
246 sigaction(SIGKILL, &kill_action, NULL);
247 sigaction(SIGHUP, &kill_action, NULL);
249 /* Parse and process input args */
250 for (i = 1; i < argc; i++) {
251 if (strcmp(argv[i], "-r") == 0) {
252 printf("\r\nLinux proxy application version 1.0\r\n");
253 return 0;
254 } else if (strcmp(argv[i], "-h") == 0) {
255 display_help_msg();
256 return 0;
257 } else if (strcmp(argv[i], "-f") == 0) {
258 if (i + 1 < argc)
259 firmware_path = argv[i + 1];
260 } else if (strcmp(argv[i], "--remoteproc") == 0) {
261 if (i + 1 < argc)
262 rproc_name = argv[i + 1];
263 }
264 }
265 if (!rproc_name)
266 rproc_name = "zynqmp_r5_remoteproc";
268 /* Bring up remote firmware */
269 printf("\r\nMaster>Loading remote firmware\r\n");
271 if (firmware_path) {
272 /* Copy the firmware to the preferred firmware location */
273 sprintf(sys_cmd, "cp %s %s", firmware_path, fw_dst_path);
274 system(sys_cmd);
275 }
276 sprintf(sys_cmd, "modprobe %s firmware=r5_image_rpc_demo", rproc_name);
277 system(sys_cmd);
279 /* Create rpmsg proxy device */
280 printf("\r\nMaster>Create rpmsg proxy device\r\n");
281 system("modprobe rpmsg_proxy_dev_driver");
283 /* Allocate memory for proxy data structure */
284 proxy = malloc(sizeof(struct _proxy_data));
285 if (proxy == 0) {
286 printf("\r\nMaster>Failed to allocate memory.\r\n");
287 return -1;
288 }
289 proxy->active = 1;
291 /* Open proxy rpmsg device */
292 printf("\r\nMaster>Opening rpmsg proxy device\r\n");
293 i = 0;
294 do {
295 proxy->rpmsg_proxy_fd = open("/dev/rpmsg_proxy0", O_RDWR);
296 sleep(1);
297 } while (proxy->rpmsg_proxy_fd < 0 && (i++ < 2));
299 if (proxy->rpmsg_proxy_fd < 0) {
300 printf
301 ("\r\nMaster>Failed to open rpmsg proxy driver device file.\r\n");
302 ret = -1;
303 goto error0;
304 }
306 /* Allocate memory for rpc payloads */
307 proxy->rpc = malloc(RPC_BUFF_SIZE);
308 proxy->rpc_response = malloc(RPC_BUFF_SIZE);
310 /* RPC service starts */
311 printf("\r\nMaster>RPC service started !!\r\n");
312 while (proxy->active) {
313 /* Block on read for rpc requests from remote context */
314 do {
315 bytes_rcvd = read(proxy->rpmsg_proxy_fd, proxy->rpc,
316 RPC_BUFF_SIZE);
317 if (!proxy->active)
318 break;
319 } while (bytes_rcvd <= 0);
321 /* User event, break! */
322 if (!proxy->active)
323 break;
325 /* Handle rpc */
326 if (handle_rpc(proxy->rpc)) {
327 printf("\r\nMaster>Err:Handling remote procedure");
328 printf(" call!\r\n");
329 printf("\r\nrpc id %d\r\n", proxy->rpc->id);
330 printf("\r\nrpc int field1 %d\r\n",
331 proxy->rpc->sys_call_args.int_field1);
332 printf("\r\nrpc int field2 %d\r\n",
333 proxy->rpc->sys_call_args.int_field2);
334 break;
335 }
336 }
338 printf("\r\nMaster>RPC service exiting !!\r\n");
340 /* Send shutdown signal to remote application */
341 terminate_rpc_app();
343 /* Need to wait here for sometime to allow remote application to
344 complete its unintialization */
345 sleep(1);
347 /* Close proxy rpmsg device */
348 close(proxy->rpmsg_proxy_fd);
350 /* Free up resources */
351 free(proxy->rpc);
352 free(proxy->rpc_response);
354 error0:
355 free(proxy);
357 /* Unload drivers */
358 unload_drivers();
360 return ret;
361 }