1 /* $NetBSD: vmwgfx_msg.c,v 1.2 2021/12/18 23:45:45 riastradh Exp $ */ 2 3 // SPDX-License-Identifier: GPL-2.0 OR MIT 4 /* 5 * Copyright 2016 VMware, Inc., Palo Alto, CA., USA 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a 8 * copy of this software and associated documentation files (the 9 * "Software"), to deal in the Software without restriction, including 10 * without limitation the rights to use, copy, modify, merge, publish, 11 * distribute, sub license, and/or sell copies of the Software, and to 12 * permit persons to whom the Software is furnished to do so, subject to 13 * the following conditions: 14 * 15 * The above copyright notice and this permission notice (including the 16 * next paragraph) shall be included in all copies or substantial portions 17 * of the Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 22 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 23 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 24 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 25 * USE OR OTHER DEALINGS IN THE SOFTWARE. 26 * 27 */ 28 29 #include <sys/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: vmwgfx_msg.c,v 1.2 2021/12/18 23:45:45 riastradh Exp $"); 31 32 #include <linux/frame.h> 33 #include <linux/kernel.h> 34 #include <linux/module.h> 35 #include <linux/slab.h> 36 #include <linux/mem_encrypt.h> 37 38 #include <asm/hypervisor.h> 39 40 #include "vmwgfx_drv.h" 41 #include "vmwgfx_msg.h" 42 43 #define MESSAGE_STATUS_SUCCESS 0x0001 44 #define MESSAGE_STATUS_DORECV 0x0002 45 #define MESSAGE_STATUS_CPT 0x0010 46 #define MESSAGE_STATUS_HB 0x0080 47 48 #define RPCI_PROTOCOL_NUM 0x49435052 49 #define GUESTMSG_FLAG_COOKIE 0x80000000 50 51 #define RETRIES 3 52 53 #define VMW_HYPERVISOR_MAGIC 0x564D5868 54 55 #define VMW_PORT_CMD_MSG 30 56 #define VMW_PORT_CMD_HB_MSG 0 57 #define VMW_PORT_CMD_OPEN_CHANNEL (MSG_TYPE_OPEN << 16 | VMW_PORT_CMD_MSG) 58 #define VMW_PORT_CMD_CLOSE_CHANNEL (MSG_TYPE_CLOSE << 16 | VMW_PORT_CMD_MSG) 59 #define VMW_PORT_CMD_SENDSIZE (MSG_TYPE_SENDSIZE << 16 | VMW_PORT_CMD_MSG) 60 #define VMW_PORT_CMD_RECVSIZE (MSG_TYPE_RECVSIZE << 16 | VMW_PORT_CMD_MSG) 61 #define VMW_PORT_CMD_RECVSTATUS (MSG_TYPE_RECVSTATUS << 16 | VMW_PORT_CMD_MSG) 62 63 #define HIGH_WORD(X) ((X & 0xFFFF0000) >> 16) 64 65 #define MAX_USER_MSG_LENGTH PAGE_SIZE 66 67 static u32 vmw_msg_enabled = 1; 68 69 enum rpc_msg_type { 70 MSG_TYPE_OPEN, 71 MSG_TYPE_SENDSIZE, 72 MSG_TYPE_SENDPAYLOAD, 73 MSG_TYPE_RECVSIZE, 74 MSG_TYPE_RECVPAYLOAD, 75 MSG_TYPE_RECVSTATUS, 76 MSG_TYPE_CLOSE, 77 }; 78 79 struct rpc_channel { 80 u16 channel_id; 81 u32 cookie_high; 82 u32 cookie_low; 83 }; 84 85 86 87 /** 88 * vmw_open_channel 89 * 90 * @channel: RPC channel 91 * @protocol: 92 * 93 * Returns: 0 on success 94 */ 95 static int vmw_open_channel(struct rpc_channel *channel, unsigned int protocol) 96 { 97 unsigned long eax, ebx, ecx, edx, si = 0, di = 0; 98 99 VMW_PORT(VMW_PORT_CMD_OPEN_CHANNEL, 100 (protocol | GUESTMSG_FLAG_COOKIE), si, di, 101 0, 102 VMW_HYPERVISOR_MAGIC, 103 eax, ebx, ecx, edx, si, di); 104 105 if ((HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS) == 0) 106 return -EINVAL; 107 108 channel->channel_id = HIGH_WORD(edx); 109 channel->cookie_high = si; 110 channel->cookie_low = di; 111 112 return 0; 113 } 114 115 116 117 /** 118 * vmw_close_channel 119 * 120 * @channel: RPC channel 121 * 122 * Returns: 0 on success 123 */ 124 static int vmw_close_channel(struct rpc_channel *channel) 125 { 126 unsigned long eax, ebx, ecx, edx, si, di; 127 128 /* Set up additional parameters */ 129 si = channel->cookie_high; 130 di = channel->cookie_low; 131 132 VMW_PORT(VMW_PORT_CMD_CLOSE_CHANNEL, 133 0, si, di, 134 channel->channel_id << 16, 135 VMW_HYPERVISOR_MAGIC, 136 eax, ebx, ecx, edx, si, di); 137 138 if ((HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS) == 0) 139 return -EINVAL; 140 141 return 0; 142 } 143 144 /** 145 * vmw_port_hb_out - Send the message payload either through the 146 * high-bandwidth port if available, or through the backdoor otherwise. 147 * @channel: The rpc channel. 148 * @msg: NULL-terminated message. 149 * @hb: Whether the high-bandwidth port is available. 150 * 151 * Return: The port status. 152 */ 153 static unsigned long vmw_port_hb_out(struct rpc_channel *channel, 154 const char *msg, bool hb) 155 { 156 unsigned long si, di, eax, ebx, ecx, edx; 157 unsigned long msg_len = strlen(msg); 158 159 /* HB port can't access encrypted memory. */ 160 if (hb && !mem_encrypt_active()) { 161 unsigned long bp = channel->cookie_high; 162 163 si = (uintptr_t) msg; 164 di = channel->cookie_low; 165 166 VMW_PORT_HB_OUT( 167 (MESSAGE_STATUS_SUCCESS << 16) | VMW_PORT_CMD_HB_MSG, 168 msg_len, si, di, 169 VMWARE_HYPERVISOR_HB | (channel->channel_id << 16) | 170 VMWARE_HYPERVISOR_OUT, 171 VMW_HYPERVISOR_MAGIC, bp, 172 eax, ebx, ecx, edx, si, di); 173 174 return ebx; 175 } 176 177 /* HB port not available. Send the message 4 bytes at a time. */ 178 ecx = MESSAGE_STATUS_SUCCESS << 16; 179 while (msg_len && (HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS)) { 180 unsigned int bytes = min_t(size_t, msg_len, 4); 181 unsigned long word = 0; 182 183 memcpy(&word, msg, bytes); 184 msg_len -= bytes; 185 msg += bytes; 186 si = channel->cookie_high; 187 di = channel->cookie_low; 188 189 VMW_PORT(VMW_PORT_CMD_MSG | (MSG_TYPE_SENDPAYLOAD << 16), 190 word, si, di, 191 channel->channel_id << 16, 192 VMW_HYPERVISOR_MAGIC, 193 eax, ebx, ecx, edx, si, di); 194 } 195 196 return ecx; 197 } 198 199 /** 200 * vmw_port_hb_in - Receive the message payload either through the 201 * high-bandwidth port if available, or through the backdoor otherwise. 202 * @channel: The rpc channel. 203 * @reply: Pointer to buffer holding reply. 204 * @reply_len: Length of the reply. 205 * @hb: Whether the high-bandwidth port is available. 206 * 207 * Return: The port status. 208 */ 209 static unsigned long vmw_port_hb_in(struct rpc_channel *channel, char *reply, 210 unsigned long reply_len, bool hb) 211 { 212 unsigned long si, di, eax, ebx, ecx, edx; 213 214 /* HB port can't access encrypted memory */ 215 if (hb && !mem_encrypt_active()) { 216 unsigned long bp = channel->cookie_low; 217 218 si = channel->cookie_high; 219 di = (uintptr_t) reply; 220 221 VMW_PORT_HB_IN( 222 (MESSAGE_STATUS_SUCCESS << 16) | VMW_PORT_CMD_HB_MSG, 223 reply_len, si, di, 224 VMWARE_HYPERVISOR_HB | (channel->channel_id << 16), 225 VMW_HYPERVISOR_MAGIC, bp, 226 eax, ebx, ecx, edx, si, di); 227 228 return ebx; 229 } 230 231 /* HB port not available. Retrieve the message 4 bytes at a time. */ 232 ecx = MESSAGE_STATUS_SUCCESS << 16; 233 while (reply_len) { 234 unsigned int bytes = min_t(unsigned long, reply_len, 4); 235 236 si = channel->cookie_high; 237 di = channel->cookie_low; 238 239 VMW_PORT(VMW_PORT_CMD_MSG | (MSG_TYPE_RECVPAYLOAD << 16), 240 MESSAGE_STATUS_SUCCESS, si, di, 241 channel->channel_id << 16, 242 VMW_HYPERVISOR_MAGIC, 243 eax, ebx, ecx, edx, si, di); 244 245 if ((HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS) == 0) 246 break; 247 248 memcpy(reply, &ebx, bytes); 249 reply_len -= bytes; 250 reply += bytes; 251 } 252 253 return ecx; 254 } 255 256 257 /** 258 * vmw_send_msg: Sends a message to the host 259 * 260 * @channel: RPC channel 261 * @logmsg: NULL terminated string 262 * 263 * Returns: 0 on success 264 */ 265 static int vmw_send_msg(struct rpc_channel *channel, const char *msg) 266 { 267 unsigned long eax, ebx, ecx, edx, si, di; 268 size_t msg_len = strlen(msg); 269 int retries = 0; 270 271 while (retries < RETRIES) { 272 retries++; 273 274 /* Set up additional parameters */ 275 si = channel->cookie_high; 276 di = channel->cookie_low; 277 278 VMW_PORT(VMW_PORT_CMD_SENDSIZE, 279 msg_len, si, di, 280 channel->channel_id << 16, 281 VMW_HYPERVISOR_MAGIC, 282 eax, ebx, ecx, edx, si, di); 283 284 if ((HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS) == 0) { 285 /* Expected success. Give up. */ 286 return -EINVAL; 287 } 288 289 /* Send msg */ 290 ebx = vmw_port_hb_out(channel, msg, 291 !!(HIGH_WORD(ecx) & MESSAGE_STATUS_HB)); 292 293 if ((HIGH_WORD(ebx) & MESSAGE_STATUS_SUCCESS) != 0) { 294 return 0; 295 } else if ((HIGH_WORD(ebx) & MESSAGE_STATUS_CPT) != 0) { 296 /* A checkpoint occurred. Retry. */ 297 continue; 298 } else { 299 break; 300 } 301 } 302 303 return -EINVAL; 304 } 305 STACK_FRAME_NON_STANDARD(vmw_send_msg); 306 307 308 /** 309 * vmw_recv_msg: Receives a message from the host 310 * 311 * Note: It is the caller's responsibility to call kfree() on msg. 312 * 313 * @channel: channel opened by vmw_open_channel 314 * @msg: [OUT] message received from the host 315 * @msg_len: message length 316 */ 317 static int vmw_recv_msg(struct rpc_channel *channel, void **msg, 318 size_t *msg_len) 319 { 320 unsigned long eax, ebx, ecx, edx, si, di; 321 char *reply; 322 size_t reply_len; 323 int retries = 0; 324 325 326 *msg_len = 0; 327 *msg = NULL; 328 329 while (retries < RETRIES) { 330 retries++; 331 332 /* Set up additional parameters */ 333 si = channel->cookie_high; 334 di = channel->cookie_low; 335 336 VMW_PORT(VMW_PORT_CMD_RECVSIZE, 337 0, si, di, 338 channel->channel_id << 16, 339 VMW_HYPERVISOR_MAGIC, 340 eax, ebx, ecx, edx, si, di); 341 342 if ((HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS) == 0) { 343 DRM_ERROR("Failed to get reply size for host message.\n"); 344 return -EINVAL; 345 } 346 347 /* No reply available. This is okay. */ 348 if ((HIGH_WORD(ecx) & MESSAGE_STATUS_DORECV) == 0) 349 return 0; 350 351 reply_len = ebx; 352 reply = kzalloc(reply_len + 1, GFP_KERNEL); 353 if (!reply) { 354 DRM_ERROR("Cannot allocate memory for host message reply.\n"); 355 return -ENOMEM; 356 } 357 358 359 /* Receive buffer */ 360 ebx = vmw_port_hb_in(channel, reply, reply_len, 361 !!(HIGH_WORD(ecx) & MESSAGE_STATUS_HB)); 362 if ((HIGH_WORD(ebx) & MESSAGE_STATUS_SUCCESS) == 0) { 363 kfree(reply); 364 reply = NULL; 365 if ((HIGH_WORD(ebx) & MESSAGE_STATUS_CPT) != 0) { 366 /* A checkpoint occurred. Retry. */ 367 continue; 368 } 369 370 return -EINVAL; 371 } 372 373 reply[reply_len] = '\0'; 374 375 376 /* Ack buffer */ 377 si = channel->cookie_high; 378 di = channel->cookie_low; 379 380 VMW_PORT(VMW_PORT_CMD_RECVSTATUS, 381 MESSAGE_STATUS_SUCCESS, si, di, 382 channel->channel_id << 16, 383 VMW_HYPERVISOR_MAGIC, 384 eax, ebx, ecx, edx, si, di); 385 386 if ((HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS) == 0) { 387 kfree(reply); 388 reply = NULL; 389 if ((HIGH_WORD(ecx) & MESSAGE_STATUS_CPT) != 0) { 390 /* A checkpoint occurred. Retry. */ 391 continue; 392 } 393 394 return -EINVAL; 395 } 396 397 break; 398 } 399 400 if (!reply) 401 return -EINVAL; 402 403 *msg_len = reply_len; 404 *msg = reply; 405 406 return 0; 407 } 408 STACK_FRAME_NON_STANDARD(vmw_recv_msg); 409 410 411 /** 412 * vmw_host_get_guestinfo: Gets a GuestInfo parameter 413 * 414 * Gets the value of a GuestInfo.* parameter. The value returned will be in 415 * a string, and it is up to the caller to post-process. 416 * 417 * @guest_info_param: Parameter to get, e.g. GuestInfo.svga.gl3 418 * @buffer: if NULL, *reply_len will contain reply size. 419 * @length: size of the reply_buf. Set to size of reply upon return 420 * 421 * Returns: 0 on success 422 */ 423 int vmw_host_get_guestinfo(const char *guest_info_param, 424 char *buffer, size_t *length) 425 { 426 struct rpc_channel channel; 427 char *msg, *reply = NULL; 428 size_t reply_len = 0; 429 430 if (!vmw_msg_enabled) 431 return -ENODEV; 432 433 if (!guest_info_param || !length) 434 return -EINVAL; 435 436 msg = kasprintf(GFP_KERNEL, "info-get %s", guest_info_param); 437 if (!msg) { 438 DRM_ERROR("Cannot allocate memory to get guest info \"%s\".", 439 guest_info_param); 440 return -ENOMEM; 441 } 442 443 if (vmw_open_channel(&channel, RPCI_PROTOCOL_NUM)) 444 goto out_open; 445 446 if (vmw_send_msg(&channel, msg) || 447 vmw_recv_msg(&channel, (void *) &reply, &reply_len)) 448 goto out_msg; 449 450 vmw_close_channel(&channel); 451 if (buffer && reply && reply_len > 0) { 452 /* Remove reply code, which are the first 2 characters of 453 * the reply 454 */ 455 reply_len = max(reply_len - 2, (size_t) 0); 456 reply_len = min(reply_len, *length); 457 458 if (reply_len > 0) 459 memcpy(buffer, reply + 2, reply_len); 460 } 461 462 *length = reply_len; 463 464 kfree(reply); 465 kfree(msg); 466 467 return 0; 468 469 out_msg: 470 vmw_close_channel(&channel); 471 kfree(reply); 472 out_open: 473 *length = 0; 474 kfree(msg); 475 DRM_ERROR("Failed to get guest info \"%s\".", guest_info_param); 476 477 return -EINVAL; 478 } 479 480 481 482 /** 483 * vmw_host_log: Sends a log message to the host 484 * 485 * @log: NULL terminated string 486 * 487 * Returns: 0 on success 488 */ 489 int vmw_host_log(const char *log) 490 { 491 struct rpc_channel channel; 492 char *msg; 493 int ret = 0; 494 495 496 if (!vmw_msg_enabled) 497 return -ENODEV; 498 499 if (!log) 500 return ret; 501 502 msg = kasprintf(GFP_KERNEL, "log %s", log); 503 if (!msg) { 504 DRM_ERROR("Cannot allocate memory for host log message.\n"); 505 return -ENOMEM; 506 } 507 508 if (vmw_open_channel(&channel, RPCI_PROTOCOL_NUM)) 509 goto out_open; 510 511 if (vmw_send_msg(&channel, msg)) 512 goto out_msg; 513 514 vmw_close_channel(&channel); 515 kfree(msg); 516 517 return 0; 518 519 out_msg: 520 vmw_close_channel(&channel); 521 out_open: 522 kfree(msg); 523 DRM_ERROR("Failed to send host log message.\n"); 524 525 return -EINVAL; 526 } 527 528 529 /** 530 * vmw_msg_ioctl: Sends and receveives a message to/from host from/to user-space 531 * 532 * Sends a message from user-space to host. 533 * Can also receive a result from host and return that to user-space. 534 * 535 * @dev: Identifies the drm device. 536 * @data: Pointer to the ioctl argument. 537 * @file_priv: Identifies the caller. 538 * Return: Zero on success, negative error code on error. 539 */ 540 541 int vmw_msg_ioctl(struct drm_device *dev, void *data, 542 struct drm_file *file_priv) 543 { 544 struct drm_vmw_msg_arg *arg = 545 (struct drm_vmw_msg_arg *) data; 546 struct rpc_channel channel; 547 char *msg; 548 int length; 549 550 msg = kmalloc(MAX_USER_MSG_LENGTH, GFP_KERNEL); 551 if (!msg) { 552 DRM_ERROR("Cannot allocate memory for log message.\n"); 553 return -ENOMEM; 554 } 555 556 length = strncpy_from_user(msg, (void __user *)((unsigned long)arg->send), 557 MAX_USER_MSG_LENGTH); 558 if (length < 0 || length >= MAX_USER_MSG_LENGTH) { 559 DRM_ERROR("Userspace message access failure.\n"); 560 kfree(msg); 561 return -EINVAL; 562 } 563 564 565 if (vmw_open_channel(&channel, RPCI_PROTOCOL_NUM)) { 566 DRM_ERROR("Failed to open channel.\n"); 567 goto out_open; 568 } 569 570 if (vmw_send_msg(&channel, msg)) { 571 DRM_ERROR("Failed to send message to host.\n"); 572 goto out_msg; 573 } 574 575 if (!arg->send_only) { 576 char *reply = NULL; 577 size_t reply_len = 0; 578 579 if (vmw_recv_msg(&channel, (void *) &reply, &reply_len)) { 580 DRM_ERROR("Failed to receive message from host.\n"); 581 goto out_msg; 582 } 583 if (reply && reply_len > 0) { 584 if (copy_to_user((void __user *)((unsigned long)arg->receive), 585 reply, reply_len)) { 586 DRM_ERROR("Failed to copy message to userspace.\n"); 587 kfree(reply); 588 goto out_msg; 589 } 590 arg->receive_len = (__u32)reply_len; 591 } 592 kfree(reply); 593 } 594 595 vmw_close_channel(&channel); 596 kfree(msg); 597 598 return 0; 599 600 out_msg: 601 vmw_close_channel(&channel); 602 out_open: 603 kfree(msg); 604 605 return -EINVAL; 606 } 607 608