xref: /qemu/hw/remote/mpqemu-link.c (revision 9af3d9a931156142199c61518937506bfa5475f1)
1ad22c308SElena Ufimtseva /*
2ad22c308SElena Ufimtseva  * Communication channel between QEMU and remote device process
3ad22c308SElena Ufimtseva  *
4ad22c308SElena Ufimtseva  * Copyright © 2018, 2021 Oracle and/or its affiliates.
5ad22c308SElena Ufimtseva  *
6ad22c308SElena Ufimtseva  * This work is licensed under the terms of the GNU GPL, version 2 or later.
7ad22c308SElena Ufimtseva  * See the COPYING file in the top-level directory.
8ad22c308SElena Ufimtseva  *
9ad22c308SElena Ufimtseva  */
10ad22c308SElena Ufimtseva 
11ad22c308SElena Ufimtseva #include "qemu/osdep.h"
12ad22c308SElena Ufimtseva 
13ad22c308SElena Ufimtseva #include "qemu/module.h"
14ad22c308SElena Ufimtseva #include "hw/remote/mpqemu-link.h"
15ad22c308SElena Ufimtseva #include "qapi/error.h"
16ad22c308SElena Ufimtseva #include "qemu/iov.h"
17ad22c308SElena Ufimtseva #include "qemu/error-report.h"
18ad22c308SElena Ufimtseva #include "qemu/main-loop.h"
19ad22c308SElena Ufimtseva #include "io/channel.h"
2032cad1ffSPhilippe Mathieu-Daudé #include "system/iothread.h"
21ad22c308SElena Ufimtseva #include "trace.h"
22ad22c308SElena Ufimtseva 
23ad22c308SElena Ufimtseva /*
24ad22c308SElena Ufimtseva  * Send message over the ioc QIOChannel.
25ad22c308SElena Ufimtseva  * This function is safe to call from:
26ad22c308SElena Ufimtseva  * - main loop in co-routine context. Will block the main loop if not in
27ad22c308SElena Ufimtseva  *   co-routine context;
28ad22c308SElena Ufimtseva  * - vCPU thread with no co-routine context and if the channel is not part
29ad22c308SElena Ufimtseva  *   of the main loop handling;
30ad22c308SElena Ufimtseva  * - IOThread within co-routine context, outside of co-routine context
31ad22c308SElena Ufimtseva  *   will block IOThread;
32ad22c308SElena Ufimtseva  * Returns true if no errors were encountered, false otherwise.
33ad22c308SElena Ufimtseva  */
mpqemu_msg_send(MPQemuMsg * msg,QIOChannel * ioc,Error ** errp)34ad22c308SElena Ufimtseva bool mpqemu_msg_send(MPQemuMsg *msg, QIOChannel *ioc, Error **errp)
35ad22c308SElena Ufimtseva {
36195801d7SStefan Hajnoczi     bool drop_bql = bql_locked();
37ad22c308SElena Ufimtseva     bool iothread = qemu_in_iothread();
38ad22c308SElena Ufimtseva     struct iovec send[2] = {};
39ad22c308SElena Ufimtseva     int *fds = NULL;
40ad22c308SElena Ufimtseva     size_t nfds = 0;
41ad22c308SElena Ufimtseva     bool ret = false;
42ad22c308SElena Ufimtseva 
43ad22c308SElena Ufimtseva     send[0].iov_base = msg;
44ad22c308SElena Ufimtseva     send[0].iov_len = MPQEMU_MSG_HDR_SIZE;
45ad22c308SElena Ufimtseva 
46ad22c308SElena Ufimtseva     send[1].iov_base = (void *)&msg->data;
47ad22c308SElena Ufimtseva     send[1].iov_len = msg->size;
48ad22c308SElena Ufimtseva 
49ad22c308SElena Ufimtseva     if (msg->num_fds) {
50ad22c308SElena Ufimtseva         nfds = msg->num_fds;
51ad22c308SElena Ufimtseva         fds = msg->fds;
52ad22c308SElena Ufimtseva     }
53ad22c308SElena Ufimtseva 
54ad22c308SElena Ufimtseva     /*
55ad22c308SElena Ufimtseva      * Dont use in IOThread out of co-routine context as
56ad22c308SElena Ufimtseva      * it will block IOThread.
57ad22c308SElena Ufimtseva      */
58ad22c308SElena Ufimtseva     assert(qemu_in_coroutine() || !iothread);
59ad22c308SElena Ufimtseva 
60ad22c308SElena Ufimtseva     /*
61a4a411fbSStefan Hajnoczi      * Skip unlocking/locking BQL when the IOThread is running
62ad22c308SElena Ufimtseva      * in co-routine context. Co-routine context is asserted above
63ad22c308SElena Ufimtseva      * for IOThread case.
64ad22c308SElena Ufimtseva      * Also skip lock handling while in a co-routine in the main context.
65ad22c308SElena Ufimtseva      */
66195801d7SStefan Hajnoczi     if (drop_bql && !iothread && !qemu_in_coroutine()) {
67195801d7SStefan Hajnoczi         bql_unlock();
68ad22c308SElena Ufimtseva     }
69ad22c308SElena Ufimtseva 
70ad22c308SElena Ufimtseva     if (!qio_channel_writev_full_all(ioc, send, G_N_ELEMENTS(send),
71b88651cbSLeonardo Bras                                     fds, nfds, 0, errp)) {
72ad22c308SElena Ufimtseva         ret = true;
73ad22c308SElena Ufimtseva     } else {
74ad22c308SElena Ufimtseva         trace_mpqemu_send_io_error(msg->cmd, msg->size, nfds);
75ad22c308SElena Ufimtseva     }
76ad22c308SElena Ufimtseva 
77195801d7SStefan Hajnoczi     if (drop_bql && !iothread && !qemu_in_coroutine()) {
78ad22c308SElena Ufimtseva         /* See above comment why skip locking here. */
79195801d7SStefan Hajnoczi         bql_lock();
80ad22c308SElena Ufimtseva     }
81ad22c308SElena Ufimtseva 
82ad22c308SElena Ufimtseva     return ret;
83ad22c308SElena Ufimtseva }
84ad22c308SElena Ufimtseva 
85ad22c308SElena Ufimtseva /*
86ad22c308SElena Ufimtseva  * Read message from the ioc QIOChannel.
87ad22c308SElena Ufimtseva  * This function is safe to call from:
88ad22c308SElena Ufimtseva  * - From main loop in co-routine context. Will block the main loop if not in
89ad22c308SElena Ufimtseva  *   co-routine context;
90ad22c308SElena Ufimtseva  * - From vCPU thread with no co-routine context and if the channel is not part
91ad22c308SElena Ufimtseva  *   of the main loop handling;
92ad22c308SElena Ufimtseva  * - From IOThread within co-routine context, outside of co-routine context
93ad22c308SElena Ufimtseva  *   will block IOThread;
94ad22c308SElena Ufimtseva  */
mpqemu_read(QIOChannel * ioc,void * buf,size_t len,int ** fds,size_t * nfds,Error ** errp)95ad22c308SElena Ufimtseva static ssize_t mpqemu_read(QIOChannel *ioc, void *buf, size_t len, int **fds,
96ad22c308SElena Ufimtseva                            size_t *nfds, Error **errp)
97ad22c308SElena Ufimtseva {
98ad22c308SElena Ufimtseva     struct iovec iov = { .iov_base = buf, .iov_len = len };
99195801d7SStefan Hajnoczi     bool drop_bql = bql_locked();
100ad22c308SElena Ufimtseva     bool iothread = qemu_in_iothread();
101ad22c308SElena Ufimtseva     int ret = -1;
102ad22c308SElena Ufimtseva 
103ad22c308SElena Ufimtseva     /*
104ad22c308SElena Ufimtseva      * Dont use in IOThread out of co-routine context as
105ad22c308SElena Ufimtseva      * it will block IOThread.
106ad22c308SElena Ufimtseva      */
107ad22c308SElena Ufimtseva     assert(qemu_in_coroutine() || !iothread);
108ad22c308SElena Ufimtseva 
109195801d7SStefan Hajnoczi     if (drop_bql && !iothread && !qemu_in_coroutine()) {
110195801d7SStefan Hajnoczi         bql_unlock();
111ad22c308SElena Ufimtseva     }
112ad22c308SElena Ufimtseva 
113*a25b0130SFabiano Rosas     ret = qio_channel_readv_full_all_eof(ioc, &iov, 1, fds, nfds, 0, errp);
114ad22c308SElena Ufimtseva 
115195801d7SStefan Hajnoczi     if (drop_bql && !iothread && !qemu_in_coroutine()) {
116195801d7SStefan Hajnoczi         bql_lock();
117ad22c308SElena Ufimtseva     }
118ad22c308SElena Ufimtseva 
119ad22c308SElena Ufimtseva     return (ret <= 0) ? ret : iov.iov_len;
120ad22c308SElena Ufimtseva }
121ad22c308SElena Ufimtseva 
mpqemu_msg_recv(MPQemuMsg * msg,QIOChannel * ioc,Error ** errp)122ad22c308SElena Ufimtseva bool mpqemu_msg_recv(MPQemuMsg *msg, QIOChannel *ioc, Error **errp)
123ad22c308SElena Ufimtseva {
124ad22c308SElena Ufimtseva     ERRP_GUARD();
125ad22c308SElena Ufimtseva     g_autofree int *fds = NULL;
126ad22c308SElena Ufimtseva     size_t nfds = 0;
127ad22c308SElena Ufimtseva     ssize_t len;
128ad22c308SElena Ufimtseva     bool ret = false;
129ad22c308SElena Ufimtseva 
130ad22c308SElena Ufimtseva     len = mpqemu_read(ioc, msg, MPQEMU_MSG_HDR_SIZE, &fds, &nfds, errp);
131ad22c308SElena Ufimtseva     if (len <= 0) {
132ad22c308SElena Ufimtseva         goto fail;
133ad22c308SElena Ufimtseva     } else if (len != MPQEMU_MSG_HDR_SIZE) {
134ad22c308SElena Ufimtseva         error_setg(errp, "Message header corrupted");
135ad22c308SElena Ufimtseva         goto fail;
136ad22c308SElena Ufimtseva     }
137ad22c308SElena Ufimtseva 
138ad22c308SElena Ufimtseva     if (msg->size > sizeof(msg->data)) {
139ad22c308SElena Ufimtseva         error_setg(errp, "Invalid size for message");
140ad22c308SElena Ufimtseva         goto fail;
141ad22c308SElena Ufimtseva     }
142ad22c308SElena Ufimtseva 
143ad22c308SElena Ufimtseva     if (!msg->size) {
144ad22c308SElena Ufimtseva         goto copy_fds;
145ad22c308SElena Ufimtseva     }
146ad22c308SElena Ufimtseva 
147ad22c308SElena Ufimtseva     len = mpqemu_read(ioc, &msg->data, msg->size, NULL, NULL, errp);
148ad22c308SElena Ufimtseva     if (len <= 0) {
149ad22c308SElena Ufimtseva         goto fail;
150ad22c308SElena Ufimtseva     }
151ad22c308SElena Ufimtseva     if (len != msg->size) {
152ad22c308SElena Ufimtseva         error_setg(errp, "Unable to read full message");
153ad22c308SElena Ufimtseva         goto fail;
154ad22c308SElena Ufimtseva     }
155ad22c308SElena Ufimtseva 
156ad22c308SElena Ufimtseva copy_fds:
157ad22c308SElena Ufimtseva     msg->num_fds = nfds;
158ad22c308SElena Ufimtseva     if (nfds > G_N_ELEMENTS(msg->fds)) {
159ad22c308SElena Ufimtseva         error_setg(errp,
160ad22c308SElena Ufimtseva                    "Overflow error: received %zu fds, more than max of %d fds",
161ad22c308SElena Ufimtseva                    nfds, REMOTE_MAX_FDS);
162ad22c308SElena Ufimtseva         goto fail;
163ad22c308SElena Ufimtseva     }
164ad22c308SElena Ufimtseva     if (nfds) {
165ad22c308SElena Ufimtseva         memcpy(msg->fds, fds, nfds * sizeof(int));
166ad22c308SElena Ufimtseva     }
167ad22c308SElena Ufimtseva 
168ad22c308SElena Ufimtseva     ret = true;
169ad22c308SElena Ufimtseva 
170ad22c308SElena Ufimtseva fail:
171ad22c308SElena Ufimtseva     if (*errp) {
172ad22c308SElena Ufimtseva         trace_mpqemu_recv_io_error(msg->cmd, msg->size, nfds);
173ad22c308SElena Ufimtseva     }
174ad22c308SElena Ufimtseva     while (*errp && nfds) {
175ad22c308SElena Ufimtseva         close(fds[nfds - 1]);
176ad22c308SElena Ufimtseva         nfds--;
177ad22c308SElena Ufimtseva     }
178ad22c308SElena Ufimtseva 
179ad22c308SElena Ufimtseva     return ret;
180ad22c308SElena Ufimtseva }
181ad22c308SElena Ufimtseva 
182e7b2c9eaSElena Ufimtseva /*
183e7b2c9eaSElena Ufimtseva  * Send msg and wait for a reply with command code RET_MSG.
184e7b2c9eaSElena Ufimtseva  * Returns the message received of size u64 or UINT64_MAX
185e7b2c9eaSElena Ufimtseva  * on error.
186e7b2c9eaSElena Ufimtseva  * Called from VCPU thread in non-coroutine context.
187e7b2c9eaSElena Ufimtseva  * Used by the Proxy object to communicate to remote processes.
188e7b2c9eaSElena Ufimtseva  */
mpqemu_msg_send_and_await_reply(MPQemuMsg * msg,PCIProxyDev * pdev,Error ** errp)189e7b2c9eaSElena Ufimtseva uint64_t mpqemu_msg_send_and_await_reply(MPQemuMsg *msg, PCIProxyDev *pdev,
190e7b2c9eaSElena Ufimtseva                                          Error **errp)
191e7b2c9eaSElena Ufimtseva {
192e7b2c9eaSElena Ufimtseva     MPQemuMsg msg_reply = {0};
193e7b2c9eaSElena Ufimtseva     uint64_t ret = UINT64_MAX;
194e7b2c9eaSElena Ufimtseva 
195e7b2c9eaSElena Ufimtseva     assert(!qemu_in_coroutine());
196e7b2c9eaSElena Ufimtseva 
197e7b2c9eaSElena Ufimtseva     QEMU_LOCK_GUARD(&pdev->io_mutex);
198e7b2c9eaSElena Ufimtseva     if (!mpqemu_msg_send(msg, pdev->ioc, errp)) {
199e7b2c9eaSElena Ufimtseva         return ret;
200e7b2c9eaSElena Ufimtseva     }
201e7b2c9eaSElena Ufimtseva 
202e7b2c9eaSElena Ufimtseva     if (!mpqemu_msg_recv(&msg_reply, pdev->ioc, errp)) {
203e7b2c9eaSElena Ufimtseva         return ret;
204e7b2c9eaSElena Ufimtseva     }
205e7b2c9eaSElena Ufimtseva 
20611ab8725SElena Ufimtseva     if (!mpqemu_msg_valid(&msg_reply) || msg_reply.cmd != MPQEMU_CMD_RET) {
207e7b2c9eaSElena Ufimtseva         error_setg(errp, "ERROR: Invalid reply received for command %d",
208e7b2c9eaSElena Ufimtseva                          msg->cmd);
209e7b2c9eaSElena Ufimtseva         return ret;
210e7b2c9eaSElena Ufimtseva     }
211e7b2c9eaSElena Ufimtseva 
212e7b2c9eaSElena Ufimtseva     return msg_reply.data.u64;
213e7b2c9eaSElena Ufimtseva }
214e7b2c9eaSElena Ufimtseva 
mpqemu_msg_valid(MPQemuMsg * msg)215ad22c308SElena Ufimtseva bool mpqemu_msg_valid(MPQemuMsg *msg)
216ad22c308SElena Ufimtseva {
217dcf20655SJagannathan Raman     if (msg->cmd >= MPQEMU_CMD_MAX || msg->cmd < 0) {
218ad22c308SElena Ufimtseva         return false;
219ad22c308SElena Ufimtseva     }
220ad22c308SElena Ufimtseva 
221ad22c308SElena Ufimtseva     /* Verify FDs. */
222ad22c308SElena Ufimtseva     if (msg->num_fds >= REMOTE_MAX_FDS) {
223ad22c308SElena Ufimtseva         return false;
224ad22c308SElena Ufimtseva     }
225ad22c308SElena Ufimtseva 
226ad22c308SElena Ufimtseva     if (msg->num_fds > 0) {
227ad22c308SElena Ufimtseva         for (int i = 0; i < msg->num_fds; i++) {
228ad22c308SElena Ufimtseva             if (fcntl(msg->fds[i], F_GETFL) == -1) {
229ad22c308SElena Ufimtseva                 return false;
230ad22c308SElena Ufimtseva             }
231ad22c308SElena Ufimtseva         }
232ad22c308SElena Ufimtseva     }
233ad22c308SElena Ufimtseva 
234ed5d0019SJagannathan Raman      /* Verify message specific fields. */
235ed5d0019SJagannathan Raman     switch (msg->cmd) {
236ed5d0019SJagannathan Raman     case MPQEMU_CMD_SYNC_SYSMEM:
237ed5d0019SJagannathan Raman         if (msg->num_fds == 0 || msg->size != sizeof(SyncSysmemMsg)) {
238ed5d0019SJagannathan Raman             return false;
239ed5d0019SJagannathan Raman         }
240ed5d0019SJagannathan Raman         break;
24111ab8725SElena Ufimtseva     case MPQEMU_CMD_PCI_CFGWRITE:
24211ab8725SElena Ufimtseva     case MPQEMU_CMD_PCI_CFGREAD:
24311ab8725SElena Ufimtseva         if (msg->size != sizeof(PciConfDataMsg)) {
24411ab8725SElena Ufimtseva             return false;
24511ab8725SElena Ufimtseva         }
24611ab8725SElena Ufimtseva         break;
2477ee3f823SJagannathan Raman     case MPQEMU_CMD_BAR_WRITE:
2487ee3f823SJagannathan Raman     case MPQEMU_CMD_BAR_READ:
2497ee3f823SJagannathan Raman         if ((msg->size != sizeof(BarAccessMsg)) || (msg->num_fds != 0)) {
2507ee3f823SJagannathan Raman             return false;
2517ee3f823SJagannathan Raman         }
2527ee3f823SJagannathan Raman         break;
253bd36adb8SJagannathan Raman     case MPQEMU_CMD_SET_IRQFD:
254bd36adb8SJagannathan Raman         if (msg->size || (msg->num_fds != 2)) {
255bd36adb8SJagannathan Raman             return false;
256bd36adb8SJagannathan Raman         }
257bd36adb8SJagannathan Raman         break;
258ed5d0019SJagannathan Raman     default:
259ed5d0019SJagannathan Raman         break;
260ed5d0019SJagannathan Raman     }
261ed5d0019SJagannathan Raman 
262ad22c308SElena Ufimtseva     return true;
263ad22c308SElena Ufimtseva }
264