• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2016 VMware, Inc., Palo Alto, CA., USA
3  * All Rights Reserved.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the
7  * "Software"), to deal in the Software without restriction, including
8  * without limitation the rights to use, copy, modify, merge, publish,
9  * distribute, sub license, and/or sell copies of the Software, and to
10  * permit persons to whom the Software is furnished to do so, subject to
11  * the following conditions:
12  *
13  * The above copyright notice and this permission notice (including the
14  * next paragraph) shall be included in all copies or substantial portions
15  * of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
20  * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
21  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
22  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
23  * USE OR OTHER DEALINGS IN THE SOFTWARE.
24  *
25  */
26 
27 #include "util/u_math.h" /* for MAX2/MIN2 */
28 #include "util/u_debug.h"
29 #include "util/u_memory.h"
30 #include "util/u_string.h"
31 #include "pipe/p_defines.h"
32 #include "svga_msg.h"
33 
34 
35 #define MESSAGE_STATUS_SUCCESS  0x0001
36 #define MESSAGE_STATUS_DORECV   0x0002
37 #define MESSAGE_STATUS_CPT      0x0010
38 #define MESSAGE_STATUS_HB       0x0080
39 
40 #define RPCI_PROTOCOL_NUM       0x49435052
41 #define GUESTMSG_FLAG_COOKIE    0x80000000
42 
43 #define RETRIES                 3
44 
45 #define VMW_HYPERVISOR_MAGIC    0x564D5868
46 #define VMW_HYPERVISOR_PORT     0x5658
47 #define VMW_HYPERVISOR_HB_PORT  0x5659
48 
49 #define VMW_PORT_CMD_MSG        30
50 #define VMW_PORT_CMD_HB_MSG     0
51 #define VMW_PORT_CMD_OPEN_CHANNEL  (MSG_TYPE_OPEN << 16 | VMW_PORT_CMD_MSG)
52 #define VMW_PORT_CMD_CLOSE_CHANNEL (MSG_TYPE_CLOSE << 16 | VMW_PORT_CMD_MSG)
53 #define VMW_PORT_CMD_SENDSIZE   (MSG_TYPE_SENDSIZE << 16 | VMW_PORT_CMD_MSG)
54 #define VMW_PORT_CMD_RECVSIZE   (MSG_TYPE_RECVSIZE << 16 | VMW_PORT_CMD_MSG)
55 #define VMW_PORT_CMD_RECVSTATUS (MSG_TYPE_RECVSTATUS << 16 | VMW_PORT_CMD_MSG)
56 
57 #define HIGH_WORD(X) ((X & 0xFFFF0000) >> 16)
58 
59 
60 #if defined(PIPE_CC_GCC) && (PIPE_CC_GCC_VERSION > 502)
61 
62 /**
63  * Hypervisor-specific bi-directional communication channel.  Should never
64  * execute on bare metal hardware.  The caller must make sure to check for
65  * supported hypervisor before using these macros.
66  *
67  * The last two parameters are both input and output and must be initialized.
68  *
69  * @cmd: [IN] Message Cmd
70  * @in_bx: [IN] Message Len, through BX
71  * @in_si: [IN] Input argument through SI, set to 0 if not used
72  * @in_di: [IN] Input argument through DI, set ot 0 if not used
73  * @port_num: [IN] port number + [channel id]
74  * @magic: [IN] hypervisor magic value
75  * @ax: [OUT] value of AX register
76  * @bx: [OUT] e.g. status from an HB message status command
77  * @cx: [OUT] e.g. status from a non-HB message status command
78  * @dx: [OUT] e.g. channel id
79  * @si:  [OUT]
80  * @di:  [OUT]
81  */
82 #define VMW_PORT(cmd, in_bx, in_si, in_di, \
83          port_num, magic,                  \
84          ax, bx, cx, dx, si, di)           \
85 ({                                         \
86    __asm__ volatile ("inl %%dx, %%eax;" :  \
87       "=a"(ax),                            \
88       "=b"(bx),                            \
89       "=c"(cx),                            \
90       "=d"(dx),                            \
91       "=S"(si),                            \
92       "=D"(di) :                           \
93       "a"(magic),                          \
94       "b"(in_bx),                          \
95       "c"(cmd),                            \
96       "d"(port_num),                       \
97       "S"(in_si),                          \
98       "D"(in_di) :                         \
99       "memory");                           \
100 })
101 
102 
103 
104 /**
105  * Hypervisor-specific bi-directional communication channel.  Should never
106  * execute on bare metal hardware.  The caller must make sure to check for
107  * supported hypervisor before using these macros.
108  *
109  * @cmd: [IN] Message Cmd
110  * @in_cx: [IN] Message Len, through CX
111  * @in_si: [IN] Input argument through SI, set to 0 if not used
112  * @in_di: [IN] Input argument through DI, set to 0 if not used
113  * @port_num: [IN] port number + [channel id]
114  * @magic: [IN] hypervisor magic value
115  * @bp:  [IN]
116  * @ax: [OUT] value of AX register
117  * @bx: [OUT] e.g. status from an HB message status command
118  * @cx: [OUT] e.g. status from a non-HB message status command
119  * @dx: [OUT] e.g. channel id
120  * @si:  [OUT]
121  * @di:  [OUT]
122  */
123 #if defined(PIPE_ARCH_X86_64)
124 
125 typedef uint64_t VMW_REG;
126 
127 #define VMW_PORT_HB_OUT(cmd, in_cx, in_si, in_di, \
128          port_num, magic, bp,                     \
129          ax, bx, cx, dx, si, di)                  \
130 ({                                                \
131    __asm__ volatile ("push %%rbp;"                \
132       "movq %12, %%rbp;"                          \
133       "rep outsb;"                                \
134       "pop %%rbp;" :                              \
135       "=a"(ax),                                   \
136       "=b"(bx),                                   \
137       "=c"(cx),                                   \
138       "=d"(dx),                                   \
139       "=S"(si),                                   \
140       "=D"(di) :                                  \
141       "a"(magic),                                 \
142       "b"(cmd),                                   \
143       "c"(in_cx),                                 \
144       "d"(port_num),                              \
145       "S"(in_si),                                 \
146       "D"(in_di),                                 \
147       "r"(bp) :                                   \
148       "memory", "cc");                            \
149 })
150 
151 #define VMW_PORT_HB_IN(cmd, in_cx, in_si, in_di,  \
152          port_num, magic, bp,                     \
153          ax, bx, cx, dx, si, di)                  \
154 ({                                                \
155    __asm__ volatile ("push %%rbp;"                \
156       "movq %12, %%rbp;"                          \
157       "rep insb;"                                 \
158       "pop %%rbp" :                               \
159       "=a"(ax),                                   \
160       "=b"(bx),                                   \
161       "=c"(cx),                                   \
162       "=d"(dx),                                   \
163       "=S"(si),                                   \
164       "=D"(di) :                                  \
165       "a"(magic),                                 \
166       "b"(cmd),                                   \
167       "c"(in_cx),                                 \
168       "d"(port_num),                              \
169       "S"(in_si),                                 \
170       "D"(in_di),                                 \
171       "r"(bp) :                                   \
172       "memory", "cc");                            \
173 })
174 
175 #else
176 
177 typedef uint32_t VMW_REG;
178 
179 /* In the 32-bit version of this macro, we use "m" because there is no
180  * more register left for bp
181  */
182 #define VMW_PORT_HB_OUT(cmd, in_cx, in_si, in_di, \
183          port_num, magic, bp,                     \
184          ax, bx, cx, dx, si, di)                  \
185 ({                                                \
186    __asm__ volatile ("push %%ebp;"                \
187       "mov %12, %%ebp;"                           \
188       "rep outsb;"                                \
189       "pop %%ebp;" :                              \
190       "=a"(ax),                                   \
191       "=b"(bx),                                   \
192       "=c"(cx),                                   \
193       "=d"(dx),                                   \
194       "=S"(si),                                   \
195       "=D"(di) :                                  \
196       "a"(magic),                                 \
197       "b"(cmd),                                   \
198       "c"(in_cx),                                 \
199       "d"(port_num),                              \
200       "S"(in_si),                                 \
201       "D"(in_di),                                 \
202       "m"(bp) :                                   \
203       "memory", "cc");                            \
204 })
205 
206 
207 #define VMW_PORT_HB_IN(cmd, in_cx, in_si, in_di,  \
208          port_num, magic, bp,                     \
209          ax, bx, cx, dx, si, di)                  \
210 ({                                                \
211    __asm__ volatile ("push %%ebp;"                \
212       "mov %12, %%ebp;"                           \
213       "rep insb;"                                 \
214       "pop %%ebp" :                               \
215       "=a"(ax),                                   \
216       "=b"(bx),                                   \
217       "=c"(cx),                                   \
218       "=d"(dx),                                   \
219       "=S"(si),                                   \
220       "=D"(di) :                                  \
221       "a"(magic),                                 \
222       "b"(cmd),                                   \
223       "c"(in_cx),                                 \
224       "d"(port_num),                              \
225       "S"(in_si),                                 \
226       "D"(in_di),                                 \
227       "m"(bp) :                                   \
228       "memory", "cc");                            \
229 })
230 
231 #endif
232 
233 #else
234 
235 #define MSG_NOT_IMPLEMENTED 1
236 
237 /* not implemented */
238 
239 typedef uint32_t VMW_REG;
240 
241 
242 #define VMW_PORT(cmd, in_bx, in_si, in_di, \
243          port_num, magic,                  \
244          ax, bx, cx, dx, si, di)           \
245          (void) in_bx;                     \
246          (void) ax; (void) bx; (void) cx;  \
247          (void) dx; (void) si; (void) di;
248 
249 #define VMW_PORT_HB_OUT(cmd, in_cx, in_si, in_di, \
250          port_num, magic, bp,                     \
251          ax, bx, cx, dx, si, di)                  \
252          (void) in_cx; (void) bp;                 \
253          (void) ax; (void) bx; (void) cx;         \
254          (void) dx; (void) si; (void) di;
255 
256 
257 #define VMW_PORT_HB_IN(cmd, in_cx, in_si, in_di,  \
258          port_num, magic, bp,                     \
259          ax, bx, cx, dx, si, di)                  \
260          (void) bp;                               \
261          (void) ax; (void) bx; (void) cx;         \
262          (void) dx; (void) si; (void) di;
263 
264 #endif /* #if PIPE_CC_GCC */
265 
266 
267 enum rpc_msg_type {
268    MSG_TYPE_OPEN,
269    MSG_TYPE_SENDSIZE,
270    MSG_TYPE_SENDPAYLOAD,
271    MSG_TYPE_RECVSIZE,
272    MSG_TYPE_RECVPAYLOAD,
273    MSG_TYPE_RECVSTATUS,
274    MSG_TYPE_CLOSE,
275 };
276 
277 struct rpc_channel {
278    uint16_t channel_id;
279    uint32_t cookie_high;
280    uint32_t cookie_low;
281 };
282 
283 
284 
285 /**
286  * svga_open_channel
287  *
288  * @channel: RPC channel
289  * @protocol:
290  *
291  * Returns: PIPE_OK on success, PIPE_ERROR otherwise
292  */
293 static enum pipe_error
svga_open_channel(struct rpc_channel * channel,unsigned protocol)294 svga_open_channel(struct rpc_channel *channel, unsigned protocol)
295 {
296    VMW_REG ax = 0, bx = 0, cx = 0, dx = 0, si = 0, di = 0;
297 
298    VMW_PORT(VMW_PORT_CMD_OPEN_CHANNEL,
299       (protocol | GUESTMSG_FLAG_COOKIE), si, di,
300       VMW_HYPERVISOR_PORT,
301       VMW_HYPERVISOR_MAGIC,
302       ax, bx, cx, dx, si, di);
303 
304    if ((HIGH_WORD(cx) & MESSAGE_STATUS_SUCCESS) == 0)
305       return PIPE_ERROR;
306 
307    channel->channel_id = HIGH_WORD(dx);
308    channel->cookie_high = si;
309    channel->cookie_low = di;
310 
311    return PIPE_OK;
312 }
313 
314 
315 
316 /**
317  * svga_close_channel
318  *
319  * @channel: RPC channel
320  *
321  * Returns: PIPE_OK on success, PIPE_ERROR otherwises
322  */
323 static enum pipe_error
svga_close_channel(struct rpc_channel * channel)324 svga_close_channel(struct rpc_channel *channel)
325 {
326    VMW_REG ax = 0, bx = 0, cx = 0, dx = 0, si, di;
327 
328    /* Set up additional parameters */
329    si = channel->cookie_high;
330    di = channel->cookie_low;
331 
332    VMW_PORT(VMW_PORT_CMD_CLOSE_CHANNEL,
333       0, si, di,
334       (VMW_HYPERVISOR_PORT | (channel->channel_id << 16)),
335       VMW_HYPERVISOR_MAGIC,
336       ax, bx, cx, dx, si, di);
337 
338    if ((HIGH_WORD(cx) & MESSAGE_STATUS_SUCCESS) == 0)
339       return PIPE_ERROR;
340 
341    return PIPE_OK;
342 }
343 
344 
345 
346 /**
347  * svga_send_msg: Sends a message to the host
348  *
349  * @channel: RPC channel
350  * @logmsg: NULL terminated string
351  *
352  * Returns: PIPE_OK on success
353  */
354 static enum pipe_error
svga_send_msg(struct rpc_channel * channel,const char * msg)355 svga_send_msg(struct rpc_channel *channel, const char *msg)
356 {
357    VMW_REG ax = 0, bx = 0, cx = 0, dx = 0, si, di, bp;
358    size_t msg_len = strlen(msg);
359    int retries = 0;
360 
361 
362    while (retries < RETRIES) {
363       retries++;
364 
365       /* Set up additional parameters */
366       si = channel->cookie_high;
367       di = channel->cookie_low;
368 
369       VMW_PORT(VMW_PORT_CMD_SENDSIZE,
370          msg_len, si, di,
371          VMW_HYPERVISOR_PORT | (channel->channel_id << 16),
372          VMW_HYPERVISOR_MAGIC,
373          ax, bx, cx, dx, si, di);
374 
375       if ((HIGH_WORD(cx) & MESSAGE_STATUS_SUCCESS) == 0 ||
376           (HIGH_WORD(cx) & MESSAGE_STATUS_HB) == 0) {
377          /* Expected success + high-bandwidth. Give up. */
378          return PIPE_ERROR;
379       }
380 
381       /* Send msg */
382       si = (uintptr_t) msg;
383       di = channel->cookie_low;
384       bp = channel->cookie_high;
385 
386       VMW_PORT_HB_OUT(
387          (MESSAGE_STATUS_SUCCESS << 16) | VMW_PORT_CMD_HB_MSG,
388          msg_len, si, di,
389          VMW_HYPERVISOR_HB_PORT | (channel->channel_id << 16),
390          VMW_HYPERVISOR_MAGIC, bp,
391          ax, bx, cx, dx, si, di);
392 
393       if ((HIGH_WORD(bx) & MESSAGE_STATUS_SUCCESS) != 0) {
394          return PIPE_OK;
395       } else if ((HIGH_WORD(bx) & MESSAGE_STATUS_CPT) != 0) {
396          /* A checkpoint occurred. Retry. */
397          continue;
398       } else {
399          break;
400       }
401    }
402 
403    return PIPE_ERROR;
404 }
405 
406 
407 
408 /**
409  * svga_host_log: Sends a log message to the host
410  *
411  * @log: NULL terminated string
412  *
413  * Returns: PIPE_OK on success
414  */
415 enum pipe_error
svga_host_log(const char * log)416 svga_host_log(const char *log)
417 {
418    struct rpc_channel channel;
419    char *msg;
420    int msg_len;
421    enum pipe_error ret = PIPE_OK;
422 
423 #ifdef MSG_NOT_IMPLEMENTED
424    return ret;
425 #endif
426 
427    if (!log)
428       return ret;
429 
430    msg_len = strlen(log) + strlen("log ") + 1;
431    msg = CALLOC(1, msg_len);
432    if (msg == NULL) {
433       debug_printf("Cannot allocate memory for log message\n");
434       return PIPE_ERROR_OUT_OF_MEMORY;
435    }
436 
437    util_sprintf(msg, "log %s", log);
438 
439    if (svga_open_channel(&channel, RPCI_PROTOCOL_NUM) ||
440        svga_send_msg(&channel, msg) ||
441        svga_close_channel(&channel)) {
442       debug_printf("Failed to send log\n");
443 
444       ret = PIPE_ERROR;
445    }
446 
447    FREE(msg);
448 
449    return ret;
450 }
451 
452