1 // SPDX-License-Identifier: BSD-3-Clause
2 //
3 // Copyright(c) 2019 Intel Corporation. All rights reserved.
4 //
5 // Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
6 // Author: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
7 
8 /*
9  * Creates an IO bridge between two QEMU instances where messages can be passed
10  * between the parent and child instances via messages queues and shared memory.
11  *
12  * The parent is usually the QEMU instance that runs the operating system (like
13  * Linux) on the application processor whilst the child is typically a smaller
14  * processor running an embedded firmware. The parent and child do not need to
15  * be the same architecture but are expected to communicate over a local bus.
16  */
17 
18 #include <mqueue.h>
19 #include <unistd.h>
20 #include <sys/mman.h>
21 #include <sys/stat.h>
22 #include <sys/types.h>
23 #include <fcntl.h>
24 #include <stdint.h>
25 #include <stdbool.h>
26 #include <stdio.h>
27 #include <glib.h>
28 #include <errno.h>
29 #include "qemu-bridge.h"
30 
31 /* set to 1 to enable debug */
32 static int io_bridge_debug;//QEMU_IO_DEBUG;
33 
34 /* we can either be parent or child */
35 #define ROLE_NONE    0
36 #define ROLE_PARENT    1
37 #define ROLE_CHILD    2
38 
39 static int role = ROLE_NONE;
40 
41 #define QEMU_IO_MAX_MSGS    8
42 #define QEMU_IO_MAX_MSG_SIZE    128
43 #define QEMU_IO_MAX_SHM_REGIONS    32
44 
45 #define NAME_SIZE       64
46 
47 struct io_shm {
48 	int fd;
49 	void *addr;
50 	char name[NAME_SIZE];
51 	size_t size;
52 };
53 
54 struct io_mq {
55 	char mq_name[NAME_SIZE];
56 	char thread_name[NAME_SIZE];
57 	struct mq_attr mqattr;
58 	mqd_t mqdes;
59 };
60 
61 struct io_bridge {
62 	struct io_mq parent;
63 	struct io_mq child;
64 	GThread *io_thread;
65 	int (*cb)(void *data, struct qemu_io_msg *msg);
66 	struct io_shm shm[QEMU_IO_MAX_SHM_REGIONS];
67 	void *data;
68 };
69 
70 static struct io_bridge _iob;
71 static int _id;
72 
73 /* parent reader Q */
parent_reader_thread(gpointer data)74 static gpointer parent_reader_thread(gpointer data)
75 {
76 	struct io_bridge *io = data;
77 	char buf[QEMU_IO_MAX_MSG_SIZE];
78 	int i;
79 
80 	mq_getattr(io->parent.mqdes, &io->parent.mqattr);
81 	if (io_bridge_debug)
82 		fprintf(stdout, "bridge-io: %d messages are currently on parent queue.\n",
83 			(int)io->parent.mqattr.mq_curmsgs);
84 
85 	while (mq_receive(io->parent.mqdes, buf, QEMU_IO_MAX_MSG_SIZE,
86 			  NULL) != -1) {
87 		struct qemu_io_msg *hdr = (struct qemu_io_msg *)buf;
88 
89 		if (io_bridge_debug)
90 			fprintf(stdout, "bridge-io: msg recv %d type %d size %d msg %d\n",
91 				hdr->id, hdr->type, hdr->size, hdr->msg);
92 
93 		if (io->cb)
94 			io->cb(io->data, hdr);
95 	}
96 
97 	return 0;
98 }
99 
100 /* child reader Q */
child_reader_thread(gpointer data)101 static gpointer child_reader_thread(gpointer data)
102 {
103 	struct io_bridge *io = data;
104 	char buf[QEMU_IO_MAX_MSG_SIZE];
105 	int i;
106 
107 	mq_getattr(io->child.mqdes, &io->child.mqattr);
108 	if (io_bridge_debug)
109 		fprintf(stdout, "bridge-io: %d messages are currently on child queue.\n",
110 			(int)io->child.mqattr.mq_curmsgs);
111 
112 	/* flush old messages here */
113 	for (i = 0; i < io->child.mqattr.mq_curmsgs; i++) {
114 		mq_receive(io->child.mqdes, buf, QEMU_IO_MAX_MSG_SIZE, NULL);
115 		struct qemu_io_msg *hdr = (struct qemu_io_msg *)buf;
116 
117 		if (io_bridge_debug)
118 			fprintf(stdout, "bridge-io: flushed %d type %d size %d msg %d\n",
119 				hdr->id, hdr->type, hdr->size, hdr->msg);
120 	}
121 
122 	while (mq_receive(io->child.mqdes, buf, QEMU_IO_MAX_MSG_SIZE,
123 			  NULL) != -1) {
124 		struct qemu_io_msg *hdr = (struct qemu_io_msg *)buf;
125 
126 		if (io_bridge_debug)
127 			fprintf(stdout, "bridge-io: msg recv %d type %d size %d msg %d\n",
128 				hdr->id, hdr->type, hdr->size, hdr->msg);
129 
130 		if (io->cb)
131 			io->cb(io->data, hdr);
132 	}
133 
134 	return 0;
135 }
136 
mq_init(const char * name,struct io_bridge * io)137 static int mq_init(const char *name, struct io_bridge *io)
138 {
139 	int ret = 0;
140 
141 	io->parent.mqattr.mq_maxmsg = QEMU_IO_MAX_MSGS;
142 	io->parent.mqattr.mq_msgsize = QEMU_IO_MAX_MSG_SIZE;
143 	io->parent.mqattr.mq_flags = 0;
144 	io->parent.mqattr.mq_curmsgs = 0;
145 
146 	io->child.mqattr.mq_maxmsg = QEMU_IO_MAX_MSGS;
147 	io->child.mqattr.mq_msgsize = QEMU_IO_MAX_MSG_SIZE;
148 	io->child.mqattr.mq_flags = 0;
149 	io->child.mqattr.mq_curmsgs = 0;
150 
151 	if (role == ROLE_PARENT) {
152 
153 		/* Host */
154 
155 		sprintf(io->parent.thread_name, "io-bridge-%s", name);
156 		io->io_thread = g_thread_new(io->parent.thread_name,
157 					     parent_reader_thread, io);
158 
159 		/* parent Rx Q */
160 		sprintf(io->parent.mq_name, "/qemu-io-parent-%s", name);
161 		io->parent.mqdes = mq_open(io->parent.mq_name,
162 					   O_RDONLY | O_CREAT,
163 					   0664, &io->parent.mqattr);
164 		if (io->parent.mqdes < 0) {
165 			fprintf(stderr, "failed to open parent Rx queue %d\n",
166 				-errno);
167 			ret = -errno;
168 		}
169 
170 		/* parent Tx Q */
171 		sprintf(io->child.mq_name, "/qemu-io-child-%s", name);
172 		io->child.mqdes = mq_open(io->child.mq_name,
173 					  O_WRONLY | O_CREAT,
174 					  0664, &io->child.mqattr);
175 		if (io->child.mqdes < 0) {
176 			fprintf(stderr, "failed to open parent Tx queue %d\n",
177 				-errno);
178 			ret = -errno;
179 		}
180 	} else {
181 
182 		/* DSP */
183 
184 		sprintf(io->child.thread_name, "io-bridge-%s", name);
185 		io->io_thread = g_thread_new(io->child.thread_name,
186 					     child_reader_thread, io);
187 
188 		/* child Rx Q */
189 		sprintf(io->child.mq_name, "/qemu-io-child-%s", name);
190 		mq_unlink(io->child.mq_name);
191 		io->child.mqdes = mq_open(io->child.mq_name,
192 					  O_RDONLY | O_CREAT,
193 					  0664, &io->child.mqattr);
194 		if (io->child.mqdes < 0) {
195 			fprintf(stderr, "failed to open child Rx queue %d\n",
196 				-errno);
197 			ret = -errno;
198 		}
199 
200 		/* child Tx Q */
201 		sprintf(io->parent.mq_name, "/qemu-io-parent-%s", name);
202 		mq_unlink(io->parent.mq_name);
203 		io->parent.mqdes = mq_open(io->parent.mq_name,
204 					   O_WRONLY | O_CREAT,
205 					   0664, &io->parent.mqattr);
206 		if (io->parent.mqdes < 0) {
207 			fprintf(stderr, "failed to open child Tx queue %d\n",
208 				-errno);
209 			ret = -errno;
210 		}
211 	}
212 
213 	if (ret == 0 && io_bridge_debug) {
214 		fprintf(stdout, "bridge-io-mq: added %s\n",
215 			io->parent.mq_name);
216 		fprintf(stdout, "bridge-io-mq: added %s\n", io->child.mq_name);
217 	}
218 
219 	return ret;
220 }
221 
qemu_io_register_parent(const char * name,int (* cb)(void *,struct qemu_io_msg * msg),void * data)222 int qemu_io_register_parent(const char *name,
223 			    int (*cb)(void *, struct qemu_io_msg *msg),
224 			    void *data)
225 {
226 	if (role != ROLE_NONE)
227 		return -EINVAL;
228 
229 	role = ROLE_PARENT;
230 	_iob.cb = cb;
231 	_iob.data = data;
232 
233 	mq_init(name, &_iob);
234 
235 	return 0;
236 }
237 
qemu_io_register_child(const char * name,int (* cb)(void *,struct qemu_io_msg * msg),void * data)238 int qemu_io_register_child(const char *name,
239 			   int (*cb)(void *, struct qemu_io_msg *msg),
240 			   void *data)
241 {
242 	int ret = 0;
243 
244 	if (role != ROLE_NONE)
245 		return -EINVAL;
246 
247 	role = ROLE_CHILD;
248 	_iob.cb = cb;
249 	_iob.data = data;
250 
251 	mq_init(name, &_iob);
252 
253 	return ret;
254 }
255 
qemu_io_register_shm(const char * rname,int region,size_t size,void ** addr)256 int qemu_io_register_shm(const char *rname, int region, size_t size,
257 			 void **addr)
258 {
259 	char *name;
260 	int fd, ret;
261 	void *a;
262 
263 	/* check that region is not already in use */
264 	if (_iob.shm[region].fd)
265 		return -EBUSY;
266 
267 	name = _iob.shm[region].name;
268 	sprintf(name, "qemu-bridge-%s", rname);
269 
270 	fd = shm_open(name, O_RDWR | O_CREAT, 0664);
271 	if (fd < 0) {
272 		fprintf(stderr, "bridge-io: can't open SHM %d\n", errno);
273 		return -errno;
274 	}
275 
276 	ret = ftruncate(fd, size);
277 	if (ret < 0) {
278 		fprintf(stderr, "bridge-io: can't truncate %d\n", errno);
279 		shm_unlink(name);
280 		return -errno;
281 	}
282 
283 	a = mmap(*addr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
284 	if (!a) {
285 		fprintf(stderr, "bridge-io: can't open mmap %d\n", errno);
286 		shm_unlink(name);
287 		return -errno;
288 	}
289 
290 	if (io_bridge_debug)
291 		fprintf(stdout, "bridge-io: %s fd %d region %d at %p allocated %zu bytes\n",
292 			name, fd, region, a, size);
293 	_iob.shm[region].fd = fd;
294 	_iob.shm[region].addr = a;
295 	_iob.shm[region].size = size;
296 	*addr = a;
297 
298 	return ret;
299 }
300 
301 #define PAGE_SIZE 4096
302 
qemu_io_sync(int region,unsigned int offset,size_t length)303 int qemu_io_sync(int region, unsigned int offset, size_t length)
304 {
305 	if (region < 0 || region > QEMU_IO_MAX_SHM_REGIONS)
306 		return -EINVAL;
307 
308 	/* check that region is in use */
309 	if (_iob.shm[region].fd == 0)
310 		return -EINVAL;
311 
312 	/* align offset to pagesize */
313 	offset -= (offset % PAGE_SIZE);
314 
315 	return msync(_iob.shm[region].addr + offset, length,
316 		     MS_SYNC | MS_INVALIDATE);
317 }
318 
qemu_io_send_msg(struct qemu_io_msg * msg)319 int qemu_io_send_msg(struct qemu_io_msg *msg)
320 {
321 	int ret;
322 
323 	msg->id = _id++;
324 
325 	if (role == ROLE_PARENT)
326 		ret = mq_send(_iob.child.mqdes, (const char *)msg, msg->size,
327 			      0);
328 	else
329 		ret = mq_send(_iob.parent.mqdes, (const char *)msg, msg->size,
330 			      0);
331 
332 	if (io_bridge_debug)
333 		fprintf(stdout, "bridge-io: msg send: %d type %d msg %d size %d ret %d\n",
334 			msg->id, msg->type, msg->msg, msg->size, ret);
335 	if (ret < 0)
336 		fprintf(stderr, "bridge-io: msg send failed %d\n", -errno);
337 
338 	return ret;
339 }
340 
qemu_io_send_msg_reply(struct qemu_io_msg * msg)341 int qemu_io_send_msg_reply(struct qemu_io_msg *msg)
342 {
343 	int ret;
344 
345 	if (role == ROLE_PARENT)
346 		ret = mq_send(_iob.child.mqdes, (const char *)msg, msg->size,
347 			      0);
348 	else
349 		ret = mq_send(_iob.parent.mqdes, (const char *)msg, msg->size,
350 			      0);
351 
352 	if (io_bridge_debug)
353 		fprintf(stdout, "bridge-io: repmsg send: %d type %d msg %d size %d ret %d\n",
354 			msg->id, msg->type, msg->msg, msg->size, ret);
355 	if (ret < 0)
356 		fprintf(stderr, "bridge-io: rmsg send failed %d\n", -errno);
357 
358 	return ret;
359 }
360 
qemu_io_free(void)361 void qemu_io_free(void)
362 {
363 	int i;
364 
365 	for (i = 0; i < QEMU_IO_MAX_SHM_REGIONS; i++) {
366 		if (_iob.shm[i].fd) {
367 			munmap(_iob.shm[i].addr, _iob.shm[i].size);
368 			shm_unlink(_iob.shm[i].name);
369 			close(_iob.shm[i].fd);
370 		}
371 	}
372 
373 	mq_unlink(_iob.parent.mq_name);
374 	mq_unlink(_iob.child.mq_name);
375 
376 	mq_close(_iob.parent.mqdes);
377 	mq_close(_iob.child.mqdes);
378 }
379 
qemu_io_free_shm(int region)380 void qemu_io_free_shm(int region)
381 {
382 	int err;
383 
384 	if (region < QEMU_IO_MAX_SHM_REGIONS && _iob.shm[region].fd) {
385 		err = munmap(_iob.shm[region].addr, _iob.shm[region].size);
386 		if (err < 0)
387 			fprintf(stderr, "bridge-io: munmap failed %d\n",
388 				errno);
389 
390 		/* client or host can unlink this, so it gets done twice */
391 		shm_unlink(_iob.shm[region].name);
392 		close(_iob.shm[region].fd);
393 		_iob.shm[region].fd = 0;
394 	}
395 }
396