Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/gallium/winsys/svga/drm/vmw_msg.c
4573 views
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_winsys.h"
33
#include "vmw_msg.h"
34
#include "vmwgfx_drm.h"
35
#include "vmw_screen.h"
36
#include "xf86drm.h"
37
38
39
#define MESSAGE_STATUS_SUCCESS 0x0001
40
#define MESSAGE_STATUS_DORECV 0x0002
41
#define MESSAGE_STATUS_CPT 0x0010
42
#define MESSAGE_STATUS_HB 0x0080
43
44
#define RPCI_PROTOCOL_NUM 0x49435052
45
#define GUESTMSG_FLAG_COOKIE 0x80000000
46
47
#define RETRIES 3
48
49
#define VMW_HYPERVISOR_MAGIC 0x564D5868
50
#define VMW_HYPERVISOR_PORT 0x5658
51
#define VMW_HYPERVISOR_HB_PORT 0x5659
52
53
#define VMW_PORT_CMD_MSG 30
54
#define VMW_PORT_CMD_HB_MSG 0
55
#define VMW_PORT_CMD_OPEN_CHANNEL (MSG_TYPE_OPEN << 16 | VMW_PORT_CMD_MSG)
56
#define VMW_PORT_CMD_CLOSE_CHANNEL (MSG_TYPE_CLOSE << 16 | VMW_PORT_CMD_MSG)
57
#define VMW_PORT_CMD_SENDSIZE (MSG_TYPE_SENDSIZE << 16 | VMW_PORT_CMD_MSG)
58
#define VMW_PORT_CMD_RECVSIZE (MSG_TYPE_RECVSIZE << 16 | VMW_PORT_CMD_MSG)
59
#define VMW_PORT_CMD_RECVSTATUS (MSG_TYPE_RECVSTATUS << 16 | VMW_PORT_CMD_MSG)
60
61
#define HIGH_WORD(X) ((X & 0xFFFF0000) >> 16)
62
63
64
#if defined(PIPE_CC_GCC) && (PIPE_CC_GCC_VERSION > 502)
65
66
/**
67
* Hypervisor-specific bi-directional communication channel. Should never
68
* execute on bare metal hardware. The caller must make sure to check for
69
* supported hypervisor before using these macros.
70
*
71
* The last two parameters are both input and output and must be initialized.
72
*
73
* @cmd: [IN] Message Cmd
74
* @in_bx: [IN] Message Len, through BX
75
* @in_si: [IN] Input argument through SI, set to 0 if not used
76
* @in_di: [IN] Input argument through DI, set ot 0 if not used
77
* @port_num: [IN] port number + [channel id]
78
* @magic: [IN] hypervisor magic value
79
* @ax: [OUT] value of AX register
80
* @bx: [OUT] e.g. status from an HB message status command
81
* @cx: [OUT] e.g. status from a non-HB message status command
82
* @dx: [OUT] e.g. channel id
83
* @si: [OUT]
84
* @di: [OUT]
85
*/
86
#define VMW_PORT(cmd, in_bx, in_si, in_di, \
87
port_num, magic, \
88
ax, bx, cx, dx, si, di) \
89
({ \
90
__asm__ volatile ("inl %%dx, %%eax;" : \
91
"=a"(ax), \
92
"=b"(bx), \
93
"=c"(cx), \
94
"=d"(dx), \
95
"=S"(si), \
96
"=D"(di) : \
97
"a"(magic), \
98
"b"(in_bx), \
99
"c"(cmd), \
100
"d"(port_num), \
101
"S"(in_si), \
102
"D"(in_di) : \
103
"memory"); \
104
})
105
106
107
108
/**
109
* Hypervisor-specific bi-directional communication channel. Should never
110
* execute on bare metal hardware. The caller must make sure to check for
111
* supported hypervisor before using these macros.
112
*
113
* @cmd: [IN] Message Cmd
114
* @in_cx: [IN] Message Len, through CX
115
* @in_si: [IN] Input argument through SI, set to 0 if not used
116
* @in_di: [IN] Input argument through DI, set to 0 if not used
117
* @port_num: [IN] port number + [channel id]
118
* @magic: [IN] hypervisor magic value
119
* @bp: [IN]
120
* @ax: [OUT] value of AX register
121
* @bx: [OUT] e.g. status from an HB message status command
122
* @cx: [OUT] e.g. status from a non-HB message status command
123
* @dx: [OUT] e.g. channel id
124
* @si: [OUT]
125
* @di: [OUT]
126
*/
127
#if defined(PIPE_ARCH_X86_64)
128
129
typedef uint64_t VMW_REG;
130
131
#define VMW_PORT_HB_OUT(cmd, in_cx, in_si, in_di, \
132
port_num, magic, bp, \
133
ax, bx, cx, dx, si, di) \
134
({ \
135
__asm__ volatile ("push %%rbp;" \
136
"movq %12, %%rbp;" \
137
"rep outsb;" \
138
"pop %%rbp;" : \
139
"=a"(ax), \
140
"=b"(bx), \
141
"=c"(cx), \
142
"=d"(dx), \
143
"=S"(si), \
144
"=D"(di) : \
145
"a"(magic), \
146
"b"(cmd), \
147
"c"(in_cx), \
148
"d"(port_num), \
149
"S"(in_si), \
150
"D"(in_di), \
151
"r"(bp) : \
152
"memory", "cc"); \
153
})
154
155
#define VMW_PORT_HB_IN(cmd, in_cx, in_si, in_di, \
156
port_num, magic, bp, \
157
ax, bx, cx, dx, si, di) \
158
({ \
159
__asm__ volatile ("push %%rbp;" \
160
"movq %12, %%rbp;" \
161
"rep insb;" \
162
"pop %%rbp" : \
163
"=a"(ax), \
164
"=b"(bx), \
165
"=c"(cx), \
166
"=d"(dx), \
167
"=S"(si), \
168
"=D"(di) : \
169
"a"(magic), \
170
"b"(cmd), \
171
"c"(in_cx), \
172
"d"(port_num), \
173
"S"(in_si), \
174
"D"(in_di), \
175
"r"(bp) : \
176
"memory", "cc"); \
177
})
178
179
#else
180
181
typedef uint32_t VMW_REG;
182
183
/* In the 32-bit version of this macro, we store bp in a memory location
184
* because we've ran out of registers.
185
* Now we can't reference that memory location while we've modified
186
* %esp or %ebp, so we first push it on the stack, just before we push
187
* %ebp, and then when we need it we read it from the stack where we
188
* just pushed it.
189
*/
190
#define VMW_PORT_HB_OUT(cmd, in_cx, in_si, in_di, \
191
port_num, magic, bp, \
192
ax, bx, cx, dx, si, di) \
193
({ \
194
__asm__ volatile ("push %12;" \
195
"push %%ebp;" \
196
"mov 0x04(%%esp), %%ebp;" \
197
"rep outsb;" \
198
"pop %%ebp;" \
199
"add $0x04, %%esp;" : \
200
"=a"(ax), \
201
"=b"(bx), \
202
"=c"(cx), \
203
"=d"(dx), \
204
"=S"(si), \
205
"=D"(di) : \
206
"a"(magic), \
207
"b"(cmd), \
208
"c"(in_cx), \
209
"d"(port_num), \
210
"S"(in_si), \
211
"D"(in_di), \
212
"m"(bp) : \
213
"memory", "cc"); \
214
})
215
216
217
#define VMW_PORT_HB_IN(cmd, in_cx, in_si, in_di, \
218
port_num, magic, bp, \
219
ax, bx, cx, dx, si, di) \
220
({ \
221
__asm__ volatile ("push %12;" \
222
"push %%ebp;" \
223
"mov 0x04(%%esp), %%ebp;" \
224
"rep insb;" \
225
"pop %%ebp;" \
226
"add $0x04, %%esp;" : \
227
"=a"(ax), \
228
"=b"(bx), \
229
"=c"(cx), \
230
"=d"(dx), \
231
"=S"(si), \
232
"=D"(di) : \
233
"a"(magic), \
234
"b"(cmd), \
235
"c"(in_cx), \
236
"d"(port_num), \
237
"S"(in_si), \
238
"D"(in_di), \
239
"m"(bp) : \
240
"memory", "cc"); \
241
})
242
243
#endif
244
245
#else
246
247
#define MSG_NOT_IMPLEMENTED 1
248
249
/* not implemented */
250
251
typedef uint32_t VMW_REG;
252
253
254
#define VMW_PORT(cmd, in_bx, in_si, in_di, \
255
port_num, magic, \
256
ax, bx, cx, dx, si, di) \
257
(void) in_bx; \
258
(void) ax; (void) bx; (void) cx; \
259
(void) dx; (void) si; (void) di;
260
261
#define VMW_PORT_HB_OUT(cmd, in_cx, in_si, in_di, \
262
port_num, magic, bp, \
263
ax, bx, cx, dx, si, di) \
264
(void) in_cx; (void) bp; \
265
(void) ax; (void) bx; (void) cx; \
266
(void) dx; (void) si; (void) di;
267
268
269
#define VMW_PORT_HB_IN(cmd, in_cx, in_si, in_di, \
270
port_num, magic, bp, \
271
ax, bx, cx, dx, si, di) \
272
(void) bp; \
273
(void) ax; (void) bx; (void) cx; \
274
(void) dx; (void) si; (void) di;
275
276
#endif /* #if PIPE_CC_GCC */
277
278
279
enum rpc_msg_type {
280
MSG_TYPE_OPEN,
281
MSG_TYPE_SENDSIZE,
282
MSG_TYPE_SENDPAYLOAD,
283
MSG_TYPE_RECVSIZE,
284
MSG_TYPE_RECVPAYLOAD,
285
MSG_TYPE_RECVSTATUS,
286
MSG_TYPE_CLOSE,
287
};
288
289
struct rpc_channel {
290
uint16_t channel_id;
291
uint32_t cookie_high;
292
uint32_t cookie_low;
293
};
294
295
296
297
/**
298
* vmw_open_channel
299
*
300
* @channel: RPC channel
301
* @protocol:
302
*
303
* Returns: PIPE_OK on success, PIPE_ERROR otherwise
304
*/
305
static enum pipe_error
306
vmw_open_channel(struct rpc_channel *channel, unsigned protocol)
307
{
308
VMW_REG ax = 0, bx = 0, cx = 0, dx = 0, si = 0, di = 0;
309
310
VMW_PORT(VMW_PORT_CMD_OPEN_CHANNEL,
311
(protocol | GUESTMSG_FLAG_COOKIE), si, di,
312
VMW_HYPERVISOR_PORT,
313
VMW_HYPERVISOR_MAGIC,
314
ax, bx, cx, dx, si, di);
315
316
if ((HIGH_WORD(cx) & MESSAGE_STATUS_SUCCESS) == 0)
317
return PIPE_ERROR;
318
319
channel->channel_id = HIGH_WORD(dx);
320
channel->cookie_high = si;
321
channel->cookie_low = di;
322
323
return PIPE_OK;
324
}
325
326
327
328
/**
329
* svga_close_channel
330
*
331
* @channel: RPC channel
332
*
333
* Returns: PIPE_OK on success, PIPE_ERROR otherwises
334
*/
335
static enum pipe_error
336
vmw_close_channel(struct rpc_channel *channel)
337
{
338
VMW_REG ax = 0, bx = 0, cx = 0, dx = 0, si, di;
339
340
/* Set up additional parameters */
341
si = channel->cookie_high;
342
di = channel->cookie_low;
343
344
VMW_PORT(VMW_PORT_CMD_CLOSE_CHANNEL,
345
0, si, di,
346
(VMW_HYPERVISOR_PORT | (channel->channel_id << 16)),
347
VMW_HYPERVISOR_MAGIC,
348
ax, bx, cx, dx, si, di);
349
350
if ((HIGH_WORD(cx) & MESSAGE_STATUS_SUCCESS) == 0)
351
return PIPE_ERROR;
352
353
return PIPE_OK;
354
}
355
356
357
358
/**
359
* vmw_send_msg: Sends a message to the host
360
*
361
* @channel: RPC channel
362
* @logmsg: NULL terminated string
363
*
364
* Returns: PIPE_OK on success
365
*/
366
static enum pipe_error
367
vmw_send_msg(struct rpc_channel *channel, const char *msg)
368
{
369
VMW_REG ax = 0, bx = 0, cx = 0, dx = 0, si, di, bp;
370
size_t msg_len = strlen(msg);
371
int retries = 0;
372
373
374
while (retries < RETRIES) {
375
retries++;
376
377
/* Set up additional parameters */
378
si = channel->cookie_high;
379
di = channel->cookie_low;
380
381
VMW_PORT(VMW_PORT_CMD_SENDSIZE,
382
msg_len, si, di,
383
VMW_HYPERVISOR_PORT | (channel->channel_id << 16),
384
VMW_HYPERVISOR_MAGIC,
385
ax, bx, cx, dx, si, di);
386
387
if ((HIGH_WORD(cx) & MESSAGE_STATUS_SUCCESS) == 0 ||
388
(HIGH_WORD(cx) & MESSAGE_STATUS_HB) == 0) {
389
/* Expected success + high-bandwidth. Give up. */
390
return PIPE_ERROR;
391
}
392
393
/* Send msg */
394
si = (uintptr_t) msg;
395
di = channel->cookie_low;
396
bp = channel->cookie_high;
397
398
VMW_PORT_HB_OUT(
399
(MESSAGE_STATUS_SUCCESS << 16) | VMW_PORT_CMD_HB_MSG,
400
msg_len, si, di,
401
VMW_HYPERVISOR_HB_PORT | (channel->channel_id << 16),
402
VMW_HYPERVISOR_MAGIC, bp,
403
ax, bx, cx, dx, si, di);
404
405
if ((HIGH_WORD(bx) & MESSAGE_STATUS_SUCCESS) != 0) {
406
return PIPE_OK;
407
} else if ((HIGH_WORD(bx) & MESSAGE_STATUS_CPT) != 0) {
408
/* A checkpoint occurred. Retry. */
409
continue;
410
} else {
411
break;
412
}
413
}
414
415
return PIPE_ERROR;
416
}
417
418
419
420
/**
421
* vmw_svga_winsys_host_log: Sends a log message to the host
422
*
423
* @log: NULL terminated string
424
*
425
*/
426
void
427
vmw_svga_winsys_host_log(struct svga_winsys_screen *sws, const char *log)
428
{
429
struct rpc_channel channel;
430
struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
431
char *msg;
432
int msg_len;
433
int ret;
434
435
#ifdef MSG_NOT_IMPLEMENTED
436
return;
437
#endif
438
439
if (!log)
440
return;
441
442
msg_len = strlen(log) + strlen("log ") + 1;
443
msg = CALLOC(1, msg_len);
444
if (msg == NULL) {
445
debug_printf("Cannot allocate memory for log message\n");
446
return;
447
}
448
449
sprintf(msg, "log %s", log);
450
451
if (vws->ioctl.have_drm_2_17) {
452
struct drm_vmw_msg_arg msg_arg;
453
454
memset(&msg_arg, 0, sizeof(msg_arg));
455
msg_arg.send = (uint64_t) (unsigned long) (msg);
456
msg_arg.send_only = 1;
457
458
ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_MSG,
459
&msg_arg, sizeof(msg_arg));
460
461
} else {
462
if (!(ret = vmw_open_channel(&channel, RPCI_PROTOCOL_NUM))) {
463
ret = vmw_send_msg(&channel, msg);
464
vmw_close_channel(&channel);
465
}
466
}
467
468
if (ret)
469
debug_printf("Failed to send log\n");
470
471
FREE(msg);
472
473
return;
474
}
475
476
477