This source file includes following definitions.
- vmw_open_channel
- vmw_close_channel
- vmw_port_hb_out
- vmw_port_hb_in
- vmw_send_msg
- vmw_recv_msg
- vmw_host_get_guestinfo
- vmw_host_log
   1 
   2 
   3 
   4 
   5 
   6 
   7 
   8 
   9 
  10 
  11 
  12 
  13 
  14 
  15 
  16 
  17 
  18 
  19 
  20 
  21 
  22 
  23 
  24 
  25 
  26 
  27 #include <linux/frame.h>
  28 #include <linux/kernel.h>
  29 #include <linux/module.h>
  30 #include <linux/slab.h>
  31 
  32 #include <asm/hypervisor.h>
  33 
  34 #include "vmwgfx_drv.h"
  35 #include "vmwgfx_msg.h"
  36 
  37 #define MESSAGE_STATUS_SUCCESS  0x0001
  38 #define MESSAGE_STATUS_DORECV   0x0002
  39 #define MESSAGE_STATUS_CPT      0x0010
  40 #define MESSAGE_STATUS_HB       0x0080
  41 
  42 #define RPCI_PROTOCOL_NUM       0x49435052
  43 #define GUESTMSG_FLAG_COOKIE    0x80000000
  44 
  45 #define RETRIES                 3
  46 
  47 #define VMW_HYPERVISOR_MAGIC    0x564D5868
  48 
  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)
  56 
  57 #define HIGH_WORD(X) ((X & 0xFFFF0000) >> 16)
  58 
  59 static u32 vmw_msg_enabled = 1;
  60 
  61 enum rpc_msg_type {
  62         MSG_TYPE_OPEN,
  63         MSG_TYPE_SENDSIZE,
  64         MSG_TYPE_SENDPAYLOAD,
  65         MSG_TYPE_RECVSIZE,
  66         MSG_TYPE_RECVPAYLOAD,
  67         MSG_TYPE_RECVSTATUS,
  68         MSG_TYPE_CLOSE,
  69 };
  70 
  71 struct rpc_channel {
  72         u16 channel_id;
  73         u32 cookie_high;
  74         u32 cookie_low;
  75 };
  76 
  77 
  78 
  79 
  80 
  81 
  82 
  83 
  84 
  85 
  86 
  87 static int vmw_open_channel(struct rpc_channel *channel, unsigned int protocol)
  88 {
  89         unsigned long eax, ebx, ecx, edx, si = 0, di = 0;
  90 
  91         VMW_PORT(VMW_PORT_CMD_OPEN_CHANNEL,
  92                 (protocol | GUESTMSG_FLAG_COOKIE), si, di,
  93                 0,
  94                 VMW_HYPERVISOR_MAGIC,
  95                 eax, ebx, ecx, edx, si, di);
  96 
  97         if ((HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS) == 0)
  98                 return -EINVAL;
  99 
 100         channel->channel_id  = HIGH_WORD(edx);
 101         channel->cookie_high = si;
 102         channel->cookie_low  = di;
 103 
 104         return 0;
 105 }
 106 
 107 
 108 
 109 
 110 
 111 
 112 
 113 
 114 
 115 
 116 static int vmw_close_channel(struct rpc_channel *channel)
 117 {
 118         unsigned long eax, ebx, ecx, edx, si, di;
 119 
 120         
 121         si  = channel->cookie_high;
 122         di  = channel->cookie_low;
 123 
 124         VMW_PORT(VMW_PORT_CMD_CLOSE_CHANNEL,
 125                 0, si, di,
 126                 channel->channel_id << 16,
 127                 VMW_HYPERVISOR_MAGIC,
 128                 eax, ebx, ecx, edx, si, di);
 129 
 130         if ((HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS) == 0)
 131                 return -EINVAL;
 132 
 133         return 0;
 134 }
 135 
 136 
 137 
 138 
 139 
 140 
 141 
 142 
 143 
 144 
 145 static unsigned long vmw_port_hb_out(struct rpc_channel *channel,
 146                                      const char *msg, bool hb)
 147 {
 148         unsigned long si, di, eax, ebx, ecx, edx;
 149         unsigned long msg_len = strlen(msg);
 150 
 151         if (hb) {
 152                 unsigned long bp = channel->cookie_high;
 153 
 154                 si = (uintptr_t) msg;
 155                 di = channel->cookie_low;
 156 
 157                 VMW_PORT_HB_OUT(
 158                         (MESSAGE_STATUS_SUCCESS << 16) | VMW_PORT_CMD_HB_MSG,
 159                         msg_len, si, di,
 160                         VMWARE_HYPERVISOR_HB | (channel->channel_id << 16) |
 161                         VMWARE_HYPERVISOR_OUT,
 162                         VMW_HYPERVISOR_MAGIC, bp,
 163                         eax, ebx, ecx, edx, si, di);
 164 
 165                 return ebx;
 166         }
 167 
 168         
 169         ecx = MESSAGE_STATUS_SUCCESS << 16;
 170         while (msg_len && (HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS)) {
 171                 unsigned int bytes = min_t(size_t, msg_len, 4);
 172                 unsigned long word = 0;
 173 
 174                 memcpy(&word, msg, bytes);
 175                 msg_len -= bytes;
 176                 msg += bytes;
 177                 si = channel->cookie_high;
 178                 di = channel->cookie_low;
 179 
 180                 VMW_PORT(VMW_PORT_CMD_MSG | (MSG_TYPE_SENDPAYLOAD << 16),
 181                          word, si, di,
 182                          channel->channel_id << 16,
 183                          VMW_HYPERVISOR_MAGIC,
 184                          eax, ebx, ecx, edx, si, di);
 185         }
 186 
 187         return ecx;
 188 }
 189 
 190 
 191 
 192 
 193 
 194 
 195 
 196 
 197 
 198 
 199 
 200 static unsigned long vmw_port_hb_in(struct rpc_channel *channel, char *reply,
 201                                     unsigned long reply_len, bool hb)
 202 {
 203         unsigned long si, di, eax, ebx, ecx, edx;
 204 
 205         if (hb) {
 206                 unsigned long bp = channel->cookie_low;
 207 
 208                 si = channel->cookie_high;
 209                 di = (uintptr_t) reply;
 210 
 211                 VMW_PORT_HB_IN(
 212                         (MESSAGE_STATUS_SUCCESS << 16) | VMW_PORT_CMD_HB_MSG,
 213                         reply_len, si, di,
 214                         VMWARE_HYPERVISOR_HB | (channel->channel_id << 16),
 215                         VMW_HYPERVISOR_MAGIC, bp,
 216                         eax, ebx, ecx, edx, si, di);
 217 
 218                 return ebx;
 219         }
 220 
 221         
 222         ecx = MESSAGE_STATUS_SUCCESS << 16;
 223         while (reply_len) {
 224                 unsigned int bytes = min_t(unsigned long, reply_len, 4);
 225 
 226                 si = channel->cookie_high;
 227                 di = channel->cookie_low;
 228 
 229                 VMW_PORT(VMW_PORT_CMD_MSG | (MSG_TYPE_RECVPAYLOAD << 16),
 230                          MESSAGE_STATUS_SUCCESS, si, di,
 231                          channel->channel_id << 16,
 232                          VMW_HYPERVISOR_MAGIC,
 233                          eax, ebx, ecx, edx, si, di);
 234 
 235                 if ((HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS) == 0)
 236                         break;
 237 
 238                 memcpy(reply, &ebx, bytes);
 239                 reply_len -= bytes;
 240                 reply += bytes;
 241         }
 242 
 243         return ecx;
 244 }
 245 
 246 
 247 
 248 
 249 
 250 
 251 
 252 
 253 
 254 
 255 static int vmw_send_msg(struct rpc_channel *channel, const char *msg)
 256 {
 257         unsigned long eax, ebx, ecx, edx, si, di;
 258         size_t msg_len = strlen(msg);
 259         int retries = 0;
 260 
 261         while (retries < RETRIES) {
 262                 retries++;
 263 
 264                 
 265                 si  = channel->cookie_high;
 266                 di  = channel->cookie_low;
 267 
 268                 VMW_PORT(VMW_PORT_CMD_SENDSIZE,
 269                         msg_len, si, di,
 270                         channel->channel_id << 16,
 271                         VMW_HYPERVISOR_MAGIC,
 272                         eax, ebx, ecx, edx, si, di);
 273 
 274                 if ((HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS) == 0) {
 275                         
 276                         return -EINVAL;
 277                 }
 278 
 279                 
 280                 ebx = vmw_port_hb_out(channel, msg,
 281                                       !!(HIGH_WORD(ecx) & MESSAGE_STATUS_HB));
 282 
 283                 if ((HIGH_WORD(ebx) & MESSAGE_STATUS_SUCCESS) != 0) {
 284                         return 0;
 285                 } else if ((HIGH_WORD(ebx) & MESSAGE_STATUS_CPT) != 0) {
 286                         
 287                         continue;
 288                 } else {
 289                         break;
 290                 }
 291         }
 292 
 293         return -EINVAL;
 294 }
 295 STACK_FRAME_NON_STANDARD(vmw_send_msg);
 296 
 297 
 298 
 299 
 300 
 301 
 302 
 303 
 304 
 305 
 306 
 307 static int vmw_recv_msg(struct rpc_channel *channel, void **msg,
 308                         size_t *msg_len)
 309 {
 310         unsigned long eax, ebx, ecx, edx, si, di;
 311         char *reply;
 312         size_t reply_len;
 313         int retries = 0;
 314 
 315 
 316         *msg_len = 0;
 317         *msg = NULL;
 318 
 319         while (retries < RETRIES) {
 320                 retries++;
 321 
 322                 
 323                 si  = channel->cookie_high;
 324                 di  = channel->cookie_low;
 325 
 326                 VMW_PORT(VMW_PORT_CMD_RECVSIZE,
 327                         0, si, di,
 328                         channel->channel_id << 16,
 329                         VMW_HYPERVISOR_MAGIC,
 330                         eax, ebx, ecx, edx, si, di);
 331 
 332                 if ((HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS) == 0) {
 333                         DRM_ERROR("Failed to get reply size for host message.\n");
 334                         return -EINVAL;
 335                 }
 336 
 337                 
 338                 if ((HIGH_WORD(ecx) & MESSAGE_STATUS_DORECV) == 0)
 339                         return 0;
 340 
 341                 reply_len = ebx;
 342                 reply     = kzalloc(reply_len + 1, GFP_KERNEL);
 343                 if (!reply) {
 344                         DRM_ERROR("Cannot allocate memory for host message reply.\n");
 345                         return -ENOMEM;
 346                 }
 347 
 348 
 349                 
 350                 ebx = vmw_port_hb_in(channel, reply, reply_len,
 351                                      !!(HIGH_WORD(ecx) & MESSAGE_STATUS_HB));
 352                 if ((HIGH_WORD(ebx) & MESSAGE_STATUS_SUCCESS) == 0) {
 353                         kfree(reply);
 354                         reply = NULL;
 355                         if ((HIGH_WORD(ebx) & MESSAGE_STATUS_CPT) != 0) {
 356                                 
 357                                 continue;
 358                         }
 359 
 360                         return -EINVAL;
 361                 }
 362 
 363                 reply[reply_len] = '\0';
 364 
 365 
 366                 
 367                 si  = channel->cookie_high;
 368                 di  = channel->cookie_low;
 369 
 370                 VMW_PORT(VMW_PORT_CMD_RECVSTATUS,
 371                         MESSAGE_STATUS_SUCCESS, si, di,
 372                         channel->channel_id << 16,
 373                         VMW_HYPERVISOR_MAGIC,
 374                         eax, ebx, ecx, edx, si, di);
 375 
 376                 if ((HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS) == 0) {
 377                         kfree(reply);
 378                         reply = NULL;
 379                         if ((HIGH_WORD(ecx) & MESSAGE_STATUS_CPT) != 0) {
 380                                 
 381                                 continue;
 382                         }
 383 
 384                         return -EINVAL;
 385                 }
 386 
 387                 break;
 388         }
 389 
 390         if (!reply)
 391                 return -EINVAL;
 392 
 393         *msg_len = reply_len;
 394         *msg     = reply;
 395 
 396         return 0;
 397 }
 398 STACK_FRAME_NON_STANDARD(vmw_recv_msg);
 399 
 400 
 401 
 402 
 403 
 404 
 405 
 406 
 407 
 408 
 409 
 410 
 411 
 412 
 413 int vmw_host_get_guestinfo(const char *guest_info_param,
 414                            char *buffer, size_t *length)
 415 {
 416         struct rpc_channel channel;
 417         char *msg, *reply = NULL;
 418         size_t reply_len = 0;
 419 
 420         if (!vmw_msg_enabled)
 421                 return -ENODEV;
 422 
 423         if (!guest_info_param || !length)
 424                 return -EINVAL;
 425 
 426         msg = kasprintf(GFP_KERNEL, "info-get %s", guest_info_param);
 427         if (!msg) {
 428                 DRM_ERROR("Cannot allocate memory to get guest info \"%s\".",
 429                           guest_info_param);
 430                 return -ENOMEM;
 431         }
 432 
 433         if (vmw_open_channel(&channel, RPCI_PROTOCOL_NUM))
 434                 goto out_open;
 435 
 436         if (vmw_send_msg(&channel, msg) ||
 437             vmw_recv_msg(&channel, (void *) &reply, &reply_len))
 438                 goto out_msg;
 439 
 440         vmw_close_channel(&channel);
 441         if (buffer && reply && reply_len > 0) {
 442                 
 443 
 444 
 445                 reply_len = max(reply_len - 2, (size_t) 0);
 446                 reply_len = min(reply_len, *length);
 447 
 448                 if (reply_len > 0)
 449                         memcpy(buffer, reply + 2, reply_len);
 450         }
 451 
 452         *length = reply_len;
 453 
 454         kfree(reply);
 455         kfree(msg);
 456 
 457         return 0;
 458 
 459 out_msg:
 460         vmw_close_channel(&channel);
 461         kfree(reply);
 462 out_open:
 463         *length = 0;
 464         kfree(msg);
 465         DRM_ERROR("Failed to get guest info \"%s\".", guest_info_param);
 466 
 467         return -EINVAL;
 468 }
 469 
 470 
 471 
 472 
 473 
 474 
 475 
 476 
 477 
 478 
 479 int vmw_host_log(const char *log)
 480 {
 481         struct rpc_channel channel;
 482         char *msg;
 483         int ret = 0;
 484 
 485 
 486         if (!vmw_msg_enabled)
 487                 return -ENODEV;
 488 
 489         if (!log)
 490                 return ret;
 491 
 492         msg = kasprintf(GFP_KERNEL, "log %s", log);
 493         if (!msg) {
 494                 DRM_ERROR("Cannot allocate memory for host log message.\n");
 495                 return -ENOMEM;
 496         }
 497 
 498         if (vmw_open_channel(&channel, RPCI_PROTOCOL_NUM))
 499                 goto out_open;
 500 
 501         if (vmw_send_msg(&channel, msg))
 502                 goto out_msg;
 503 
 504         vmw_close_channel(&channel);
 505         kfree(msg);
 506 
 507         return 0;
 508 
 509 out_msg:
 510         vmw_close_channel(&channel);
 511 out_open:
 512         kfree(msg);
 513         DRM_ERROR("Failed to send host log message.\n");
 514 
 515         return -EINVAL;
 516 }