2 * Copyright © 2016 VMware, Inc., Palo Alto, CA., USA
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:
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial portions
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.
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"
35 #define MESSAGE_STATUS_SUCCESS 0x0001
36 #define MESSAGE_STATUS_DORECV 0x0002
37 #define MESSAGE_STATUS_CPT 0x0010
38 #define MESSAGE_STATUS_HB 0x0080
40 #define RPCI_PROTOCOL_NUM 0x49435052
41 #define GUESTMSG_FLAG_COOKIE 0x80000000
45 #define VMW_HYPERVISOR_MAGIC 0x564D5868
46 #define VMW_HYPERVISOR_PORT 0x5658
47 #define VMW_HYPERVISOR_HB_PORT 0x5659
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)
57 #define HIGH_WORD(X) ((X & 0xFFFF0000) >> 16)
60 #if defined(PIPE_CC_GCC) && (PIPE_CC_GCC_VERSION > 502)
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.
67 * The last two parameters are both input and output and must be initialized.
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
82 #define VMW_PORT(cmd, in_bx, in_si, in_di, \
84 ax, bx, cx, dx, si, di) \
86 __asm__ volatile ("inl %%dx, %%eax;" : \
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.
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
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
123 #if defined(PIPE_ARCH_X86_64)
125 typedef uint64_t VMW_REG
;
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) \
131 __asm__ volatile ("push %%rbp;" \
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) \
155 __asm__ volatile ("push %%rbp;" \
177 typedef uint32_t VMW_REG
;
179 /* In the 32-bit version of this macro, we use "m" because there is no
180 * more register left for bp
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) \
186 __asm__ volatile ("push %%ebp;" \
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) \
211 __asm__ volatile ("push %%ebp;" \
235 #define MSG_NOT_IMPLEMENTED 1
237 /* not implemented */
239 typedef uint32_t VMW_REG
;
242 #define VMW_PORT(cmd, in_bx, in_si, in_di, \
244 ax, bx, cx, dx, si, di) \
246 (void) ax; (void) bx; (void) cx; \
247 (void) dx; (void) si; (void) di;
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;
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) \
261 (void) ax; (void) bx; (void) cx; \
262 (void) dx; (void) si; (void) di;
264 #endif /* #if PIPE_CC_GCC */
270 MSG_TYPE_SENDPAYLOAD
,
272 MSG_TYPE_RECVPAYLOAD
,
279 uint32_t cookie_high
;
288 * @channel: RPC channel
291 * Returns: PIPE_OK on success, PIPE_ERROR otherwise
293 static enum pipe_error
294 svga_open_channel(struct rpc_channel
*channel
, unsigned protocol
)
296 VMW_REG ax
= 0, bx
= 0, cx
= 0, dx
= 0, si
= 0, di
= 0;
298 VMW_PORT(VMW_PORT_CMD_OPEN_CHANNEL
,
299 (protocol
| GUESTMSG_FLAG_COOKIE
), si
, di
,
301 VMW_HYPERVISOR_MAGIC
,
302 ax
, bx
, cx
, dx
, si
, di
);
304 if ((HIGH_WORD(cx
) & MESSAGE_STATUS_SUCCESS
) == 0)
307 channel
->channel_id
= HIGH_WORD(dx
);
308 channel
->cookie_high
= si
;
309 channel
->cookie_low
= di
;
319 * @channel: RPC channel
321 * Returns: PIPE_OK on success, PIPE_ERROR otherwises
323 static enum pipe_error
324 svga_close_channel(struct rpc_channel
*channel
)
326 VMW_REG ax
= 0, bx
= 0, cx
= 0, dx
= 0, si
, di
;
328 /* Set up additional parameters */
329 si
= channel
->cookie_high
;
330 di
= channel
->cookie_low
;
332 VMW_PORT(VMW_PORT_CMD_CLOSE_CHANNEL
,
334 (VMW_HYPERVISOR_PORT
| (channel
->channel_id
<< 16)),
335 VMW_HYPERVISOR_MAGIC
,
336 ax
, bx
, cx
, dx
, si
, di
);
338 if ((HIGH_WORD(cx
) & MESSAGE_STATUS_SUCCESS
) == 0)
347 * svga_send_msg: Sends a message to the host
349 * @channel: RPC channel
350 * @logmsg: NULL terminated string
352 * Returns: PIPE_OK on success
354 static enum pipe_error
355 svga_send_msg(struct rpc_channel
*channel
, const char *msg
)
357 VMW_REG ax
= 0, bx
= 0, cx
= 0, dx
= 0, si
, di
, bp
;
358 size_t msg_len
= strlen(msg
);
362 while (retries
< RETRIES
) {
365 /* Set up additional parameters */
366 si
= channel
->cookie_high
;
367 di
= channel
->cookie_low
;
369 VMW_PORT(VMW_PORT_CMD_SENDSIZE
,
371 VMW_HYPERVISOR_PORT
| (channel
->channel_id
<< 16),
372 VMW_HYPERVISOR_MAGIC
,
373 ax
, bx
, cx
, dx
, si
, di
);
375 if ((HIGH_WORD(cx
) & MESSAGE_STATUS_SUCCESS
) == 0 ||
376 (HIGH_WORD(cx
) & MESSAGE_STATUS_HB
) == 0) {
377 /* Expected success + high-bandwidth. Give up. */
382 si
= (uintptr_t) msg
;
383 di
= channel
->cookie_low
;
384 bp
= channel
->cookie_high
;
387 (MESSAGE_STATUS_SUCCESS
<< 16) | VMW_PORT_CMD_HB_MSG
,
389 VMW_HYPERVISOR_HB_PORT
| (channel
->channel_id
<< 16),
390 VMW_HYPERVISOR_MAGIC
, bp
,
391 ax
, bx
, cx
, dx
, si
, di
);
393 if ((HIGH_WORD(bx
) & MESSAGE_STATUS_SUCCESS
) != 0) {
395 } else if ((HIGH_WORD(bx
) & MESSAGE_STATUS_CPT
) != 0) {
396 /* A checkpoint occurred. Retry. */
409 * svga_host_log: Sends a log message to the host
411 * @log: NULL terminated string
413 * Returns: PIPE_OK on success
416 svga_host_log(const char *log
)
418 struct rpc_channel channel
;
421 enum pipe_error ret
= PIPE_OK
;
423 #ifdef MSG_NOT_IMPLEMENTED
430 msg_len
= strlen(log
) + strlen("log ") + 1;
431 msg
= CALLOC(1, msg_len
);
433 debug_printf("Cannot allocate memory for log message\n");
434 return PIPE_ERROR_OUT_OF_MEMORY
;
437 util_sprintf(msg
, "log %s", log
);
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");