1 // SPDX-License-Identifier: GPL-2.0 OR MIT 2 /* 3 * Copyright 2016 VMware, Inc., Palo Alto, CA., USA 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 28 #include <linux/slab.h> 29 #include <linux/module.h> 30 #include <linux/kernel.h> 31 #include <linux/frame.h> 32 #include <asm/hypervisor.h> 33 #include <drm/drmP.h> 34 #include "vmwgfx_drv.h" 35 #include "vmwgfx_msg.h" 36 37 38 #define MESSAGE_STATUS_SUCCESS 0x0001 39 #define MESSAGE_STATUS_DORECV 0x0002 40 #define MESSAGE_STATUS_CPT 0x0010 41 #define MESSAGE_STATUS_HB 0x0080 42 43 #define RPCI_PROTOCOL_NUM 0x49435052 44 #define GUESTMSG_FLAG_COOKIE 0x80000000 45 46 #define RETRIES 3 47 48 #define VMW_HYPERVISOR_MAGIC 0x564D5868 49 #define VMW_HYPERVISOR_PORT 0x5658 50 #define VMW_HYPERVISOR_HB_PORT 0x5659 51 52 #define VMW_PORT_CMD_MSG 30 53 #define VMW_PORT_CMD_HB_MSG 0 54 #define VMW_PORT_CMD_OPEN_CHANNEL (MSG_TYPE_OPEN << 16 | VMW_PORT_CMD_MSG) 55 #define VMW_PORT_CMD_CLOSE_CHANNEL (MSG_TYPE_CLOSE << 16 | VMW_PORT_CMD_MSG) 56 #define VMW_PORT_CMD_SENDSIZE (MSG_TYPE_SENDSIZE << 16 | VMW_PORT_CMD_MSG) 57 #define VMW_PORT_CMD_RECVSIZE (MSG_TYPE_RECVSIZE << 16 | VMW_PORT_CMD_MSG) 58 #define VMW_PORT_CMD_RECVSTATUS (MSG_TYPE_RECVSTATUS << 16 | VMW_PORT_CMD_MSG) 59 60 #define HIGH_WORD(X) ((X & 0xFFFF0000) >> 16) 61 62 static u32 vmw_msg_enabled = 1; 63 64 enum rpc_msg_type { 65 MSG_TYPE_OPEN, 66 MSG_TYPE_SENDSIZE, 67 MSG_TYPE_SENDPAYLOAD, 68 MSG_TYPE_RECVSIZE, 69 MSG_TYPE_RECVPAYLOAD, 70 MSG_TYPE_RECVSTATUS, 71 MSG_TYPE_CLOSE, 72 }; 73 74 struct rpc_channel { 75 u16 channel_id; 76 u32 cookie_high; 77 u32 cookie_low; 78 }; 79 80 81 82 /** 83 * vmw_open_channel 84 * 85 * @channel: RPC channel 86 * @protocol: 87 * 88 * Returns: 0 on success 89 */ 90 static int vmw_open_channel(struct rpc_channel *channel, unsigned int protocol) 91 { 92 unsigned long eax, ebx, ecx, edx, si = 0, di = 0; 93 94 VMW_PORT(VMW_PORT_CMD_OPEN_CHANNEL, 95 (protocol | GUESTMSG_FLAG_COOKIE), si, di, 96 VMW_HYPERVISOR_PORT, 97 VMW_HYPERVISOR_MAGIC, 98 eax, ebx, ecx, edx, si, di); 99 100 if ((HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS) == 0) 101 return -EINVAL; 102 103 channel->channel_id = HIGH_WORD(edx); 104 channel->cookie_high = si; 105 channel->cookie_low = di; 106 107 return 0; 108 } 109 110 111 112 /** 113 * vmw_close_channel 114 * 115 * @channel: RPC channel 116 * 117 * Returns: 0 on success 118 */ 119 static int vmw_close_channel(struct rpc_channel *channel) 120 { 121 unsigned long eax, ebx, ecx, edx, si, di; 122 123 /* Set up additional parameters */ 124 si = channel->cookie_high; 125 di = channel->cookie_low; 126 127 VMW_PORT(VMW_PORT_CMD_CLOSE_CHANNEL, 128 0, si, di, 129 (VMW_HYPERVISOR_PORT | (channel->channel_id << 16)), 130 VMW_HYPERVISOR_MAGIC, 131 eax, ebx, ecx, edx, si, di); 132 133 if ((HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS) == 0) 134 return -EINVAL; 135 136 return 0; 137 } 138 139 140 141 /** 142 * vmw_send_msg: Sends a message to the host 143 * 144 * @channel: RPC channel 145 * @logmsg: NULL terminated string 146 * 147 * Returns: 0 on success 148 */ 149 static int vmw_send_msg(struct rpc_channel *channel, const char *msg) 150 { 151 unsigned long eax, ebx, ecx, edx, si, di, bp; 152 size_t msg_len = strlen(msg); 153 int retries = 0; 154 155 156 while (retries < RETRIES) { 157 retries++; 158 159 /* Set up additional parameters */ 160 si = channel->cookie_high; 161 di = channel->cookie_low; 162 163 VMW_PORT(VMW_PORT_CMD_SENDSIZE, 164 msg_len, si, di, 165 VMW_HYPERVISOR_PORT | (channel->channel_id << 16), 166 VMW_HYPERVISOR_MAGIC, 167 eax, ebx, ecx, edx, si, di); 168 169 if ((HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS) == 0 || 170 (HIGH_WORD(ecx) & MESSAGE_STATUS_HB) == 0) { 171 /* Expected success + high-bandwidth. Give up. */ 172 return -EINVAL; 173 } 174 175 /* Send msg */ 176 si = (uintptr_t) msg; 177 di = channel->cookie_low; 178 bp = channel->cookie_high; 179 180 VMW_PORT_HB_OUT( 181 (MESSAGE_STATUS_SUCCESS << 16) | VMW_PORT_CMD_HB_MSG, 182 msg_len, si, di, 183 VMW_HYPERVISOR_HB_PORT | (channel->channel_id << 16), 184 VMW_HYPERVISOR_MAGIC, bp, 185 eax, ebx, ecx, edx, si, di); 186 187 if ((HIGH_WORD(ebx) & MESSAGE_STATUS_SUCCESS) != 0) { 188 return 0; 189 } else if ((HIGH_WORD(ebx) & MESSAGE_STATUS_CPT) != 0) { 190 /* A checkpoint occurred. Retry. */ 191 continue; 192 } else { 193 break; 194 } 195 } 196 197 return -EINVAL; 198 } 199 STACK_FRAME_NON_STANDARD(vmw_send_msg); 200 201 202 /** 203 * vmw_recv_msg: Receives a message from the host 204 * 205 * Note: It is the caller's responsibility to call kfree() on msg. 206 * 207 * @channel: channel opened by vmw_open_channel 208 * @msg: [OUT] message received from the host 209 * @msg_len: message length 210 */ 211 static int vmw_recv_msg(struct rpc_channel *channel, void **msg, 212 size_t *msg_len) 213 { 214 unsigned long eax, ebx, ecx, edx, si, di, bp; 215 char *reply; 216 size_t reply_len; 217 int retries = 0; 218 219 220 *msg_len = 0; 221 *msg = NULL; 222 223 while (retries < RETRIES) { 224 retries++; 225 226 /* Set up additional parameters */ 227 si = channel->cookie_high; 228 di = channel->cookie_low; 229 230 VMW_PORT(VMW_PORT_CMD_RECVSIZE, 231 0, si, di, 232 (VMW_HYPERVISOR_PORT | (channel->channel_id << 16)), 233 VMW_HYPERVISOR_MAGIC, 234 eax, ebx, ecx, edx, si, di); 235 236 if ((HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS) == 0 || 237 (HIGH_WORD(ecx) & MESSAGE_STATUS_HB) == 0) { 238 DRM_ERROR("Failed to get reply size for host message.\n"); 239 return -EINVAL; 240 } 241 242 /* No reply available. This is okay. */ 243 if ((HIGH_WORD(ecx) & MESSAGE_STATUS_DORECV) == 0) 244 return 0; 245 246 reply_len = ebx; 247 reply = kzalloc(reply_len + 1, GFP_KERNEL); 248 if (!reply) { 249 DRM_ERROR("Cannot allocate memory for host message reply.\n"); 250 return -ENOMEM; 251 } 252 253 254 /* Receive buffer */ 255 si = channel->cookie_high; 256 di = (uintptr_t) reply; 257 bp = channel->cookie_low; 258 259 VMW_PORT_HB_IN( 260 (MESSAGE_STATUS_SUCCESS << 16) | VMW_PORT_CMD_HB_MSG, 261 reply_len, si, di, 262 VMW_HYPERVISOR_HB_PORT | (channel->channel_id << 16), 263 VMW_HYPERVISOR_MAGIC, bp, 264 eax, ebx, ecx, edx, si, di); 265 266 if ((HIGH_WORD(ebx) & MESSAGE_STATUS_SUCCESS) == 0) { 267 kfree(reply); 268 269 if ((HIGH_WORD(ebx) & MESSAGE_STATUS_CPT) != 0) { 270 /* A checkpoint occurred. Retry. */ 271 continue; 272 } 273 274 return -EINVAL; 275 } 276 277 reply[reply_len] = '\0'; 278 279 280 /* Ack buffer */ 281 si = channel->cookie_high; 282 di = channel->cookie_low; 283 284 VMW_PORT(VMW_PORT_CMD_RECVSTATUS, 285 MESSAGE_STATUS_SUCCESS, si, di, 286 (VMW_HYPERVISOR_PORT | (channel->channel_id << 16)), 287 VMW_HYPERVISOR_MAGIC, 288 eax, ebx, ecx, edx, si, di); 289 290 if ((HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS) == 0) { 291 kfree(reply); 292 293 if ((HIGH_WORD(ecx) & MESSAGE_STATUS_CPT) != 0) { 294 /* A checkpoint occurred. Retry. */ 295 continue; 296 } 297 298 return -EINVAL; 299 } 300 301 break; 302 } 303 304 if (retries == RETRIES) 305 return -EINVAL; 306 307 *msg_len = reply_len; 308 *msg = reply; 309 310 return 0; 311 } 312 STACK_FRAME_NON_STANDARD(vmw_recv_msg); 313 314 315 /** 316 * vmw_host_get_guestinfo: Gets a GuestInfo parameter 317 * 318 * Gets the value of a GuestInfo.* parameter. The value returned will be in 319 * a string, and it is up to the caller to post-process. 320 * 321 * @guest_info_param: Parameter to get, e.g. GuestInfo.svga.gl3 322 * @buffer: if NULL, *reply_len will contain reply size. 323 * @length: size of the reply_buf. Set to size of reply upon return 324 * 325 * Returns: 0 on success 326 */ 327 int vmw_host_get_guestinfo(const char *guest_info_param, 328 char *buffer, size_t *length) 329 { 330 struct rpc_channel channel; 331 char *msg, *reply = NULL; 332 size_t reply_len = 0; 333 334 if (!vmw_msg_enabled) 335 return -ENODEV; 336 337 if (!guest_info_param || !length) 338 return -EINVAL; 339 340 msg = kasprintf(GFP_KERNEL, "info-get %s", guest_info_param); 341 if (!msg) { 342 DRM_ERROR("Cannot allocate memory to get guest info \"%s\".", 343 guest_info_param); 344 return -ENOMEM; 345 } 346 347 if (vmw_open_channel(&channel, RPCI_PROTOCOL_NUM)) 348 goto out_open; 349 350 if (vmw_send_msg(&channel, msg) || 351 vmw_recv_msg(&channel, (void *) &reply, &reply_len)) 352 goto out_msg; 353 354 vmw_close_channel(&channel); 355 if (buffer && reply && reply_len > 0) { 356 /* Remove reply code, which are the first 2 characters of 357 * the reply 358 */ 359 reply_len = max(reply_len - 2, (size_t) 0); 360 reply_len = min(reply_len, *length); 361 362 if (reply_len > 0) 363 memcpy(buffer, reply + 2, reply_len); 364 } 365 366 *length = reply_len; 367 368 kfree(reply); 369 kfree(msg); 370 371 return 0; 372 373 out_msg: 374 vmw_close_channel(&channel); 375 kfree(reply); 376 out_open: 377 *length = 0; 378 kfree(msg); 379 DRM_ERROR("Failed to get guest info \"%s\".", guest_info_param); 380 381 return -EINVAL; 382 } 383 384 385 386 /** 387 * vmw_host_log: Sends a log message to the host 388 * 389 * @log: NULL terminated string 390 * 391 * Returns: 0 on success 392 */ 393 int vmw_host_log(const char *log) 394 { 395 struct rpc_channel channel; 396 char *msg; 397 int ret = 0; 398 399 400 if (!vmw_msg_enabled) 401 return -ENODEV; 402 403 if (!log) 404 return ret; 405 406 msg = kasprintf(GFP_KERNEL, "log %s", log); 407 if (!msg) { 408 DRM_ERROR("Cannot allocate memory for host log message.\n"); 409 return -ENOMEM; 410 } 411 412 if (vmw_open_channel(&channel, RPCI_PROTOCOL_NUM)) 413 goto out_open; 414 415 if (vmw_send_msg(&channel, msg)) 416 goto out_msg; 417 418 vmw_close_channel(&channel); 419 kfree(msg); 420 421 return 0; 422 423 out_msg: 424 vmw_close_channel(&channel); 425 out_open: 426 kfree(msg); 427 DRM_ERROR("Failed to send host log message.\n"); 428 429 return -EINVAL; 430 } 431