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