| .. | .. |
|---|
| 24 | 24 | * |
|---|
| 25 | 25 | */ |
|---|
| 26 | 26 | |
|---|
| 27 | | - |
|---|
| 28 | | -#include <linux/slab.h> |
|---|
| 29 | | -#include <linux/module.h> |
|---|
| 27 | +#include <linux/objtool.h> |
|---|
| 30 | 28 | #include <linux/kernel.h> |
|---|
| 31 | | -#include <linux/frame.h> |
|---|
| 29 | +#include <linux/module.h> |
|---|
| 30 | +#include <linux/slab.h> |
|---|
| 31 | +#include <linux/mem_encrypt.h> |
|---|
| 32 | + |
|---|
| 32 | 33 | #include <asm/hypervisor.h> |
|---|
| 33 | | -#include <drm/drmP.h> |
|---|
| 34 | + |
|---|
| 34 | 35 | #include "vmwgfx_drv.h" |
|---|
| 35 | 36 | #include "vmwgfx_msg.h" |
|---|
| 36 | | - |
|---|
| 37 | 37 | |
|---|
| 38 | 38 | #define MESSAGE_STATUS_SUCCESS 0x0001 |
|---|
| 39 | 39 | #define MESSAGE_STATUS_DORECV 0x0002 |
|---|
| .. | .. |
|---|
| 46 | 46 | #define RETRIES 3 |
|---|
| 47 | 47 | |
|---|
| 48 | 48 | #define VMW_HYPERVISOR_MAGIC 0x564D5868 |
|---|
| 49 | | -#define VMW_HYPERVISOR_PORT 0x5658 |
|---|
| 50 | | -#define VMW_HYPERVISOR_HB_PORT 0x5659 |
|---|
| 51 | 49 | |
|---|
| 52 | 50 | #define VMW_PORT_CMD_MSG 30 |
|---|
| 53 | 51 | #define VMW_PORT_CMD_HB_MSG 0 |
|---|
| .. | .. |
|---|
| 58 | 56 | #define VMW_PORT_CMD_RECVSTATUS (MSG_TYPE_RECVSTATUS << 16 | VMW_PORT_CMD_MSG) |
|---|
| 59 | 57 | |
|---|
| 60 | 58 | #define HIGH_WORD(X) ((X & 0xFFFF0000) >> 16) |
|---|
| 59 | + |
|---|
| 60 | +#define MAX_USER_MSG_LENGTH PAGE_SIZE |
|---|
| 61 | 61 | |
|---|
| 62 | 62 | static u32 vmw_msg_enabled = 1; |
|---|
| 63 | 63 | |
|---|
| .. | .. |
|---|
| 93 | 93 | |
|---|
| 94 | 94 | VMW_PORT(VMW_PORT_CMD_OPEN_CHANNEL, |
|---|
| 95 | 95 | (protocol | GUESTMSG_FLAG_COOKIE), si, di, |
|---|
| 96 | | - VMW_HYPERVISOR_PORT, |
|---|
| 96 | + 0, |
|---|
| 97 | 97 | VMW_HYPERVISOR_MAGIC, |
|---|
| 98 | 98 | eax, ebx, ecx, edx, si, di); |
|---|
| 99 | 99 | |
|---|
| .. | .. |
|---|
| 126 | 126 | |
|---|
| 127 | 127 | VMW_PORT(VMW_PORT_CMD_CLOSE_CHANNEL, |
|---|
| 128 | 128 | 0, si, di, |
|---|
| 129 | | - (VMW_HYPERVISOR_PORT | (channel->channel_id << 16)), |
|---|
| 129 | + channel->channel_id << 16, |
|---|
| 130 | 130 | VMW_HYPERVISOR_MAGIC, |
|---|
| 131 | 131 | eax, ebx, ecx, edx, si, di); |
|---|
| 132 | 132 | |
|---|
| .. | .. |
|---|
| 151 | 151 | unsigned long si, di, eax, ebx, ecx, edx; |
|---|
| 152 | 152 | unsigned long msg_len = strlen(msg); |
|---|
| 153 | 153 | |
|---|
| 154 | | - if (hb) { |
|---|
| 154 | + /* HB port can't access encrypted memory. */ |
|---|
| 155 | + if (hb && !mem_encrypt_active()) { |
|---|
| 155 | 156 | unsigned long bp = channel->cookie_high; |
|---|
| 156 | 157 | |
|---|
| 157 | 158 | si = (uintptr_t) msg; |
|---|
| .. | .. |
|---|
| 160 | 161 | VMW_PORT_HB_OUT( |
|---|
| 161 | 162 | (MESSAGE_STATUS_SUCCESS << 16) | VMW_PORT_CMD_HB_MSG, |
|---|
| 162 | 163 | msg_len, si, di, |
|---|
| 163 | | - VMW_HYPERVISOR_HB_PORT | (channel->channel_id << 16), |
|---|
| 164 | + VMWARE_HYPERVISOR_HB | (channel->channel_id << 16) | |
|---|
| 165 | + VMWARE_HYPERVISOR_OUT, |
|---|
| 164 | 166 | VMW_HYPERVISOR_MAGIC, bp, |
|---|
| 165 | 167 | eax, ebx, ecx, edx, si, di); |
|---|
| 166 | 168 | |
|---|
| .. | .. |
|---|
| 181 | 183 | |
|---|
| 182 | 184 | VMW_PORT(VMW_PORT_CMD_MSG | (MSG_TYPE_SENDPAYLOAD << 16), |
|---|
| 183 | 185 | word, si, di, |
|---|
| 184 | | - VMW_HYPERVISOR_PORT | (channel->channel_id << 16), |
|---|
| 186 | + channel->channel_id << 16, |
|---|
| 185 | 187 | VMW_HYPERVISOR_MAGIC, |
|---|
| 186 | 188 | eax, ebx, ecx, edx, si, di); |
|---|
| 187 | 189 | } |
|---|
| .. | .. |
|---|
| 204 | 206 | { |
|---|
| 205 | 207 | unsigned long si, di, eax, ebx, ecx, edx; |
|---|
| 206 | 208 | |
|---|
| 207 | | - if (hb) { |
|---|
| 209 | + /* HB port can't access encrypted memory */ |
|---|
| 210 | + if (hb && !mem_encrypt_active()) { |
|---|
| 208 | 211 | unsigned long bp = channel->cookie_low; |
|---|
| 209 | 212 | |
|---|
| 210 | 213 | si = channel->cookie_high; |
|---|
| .. | .. |
|---|
| 213 | 216 | VMW_PORT_HB_IN( |
|---|
| 214 | 217 | (MESSAGE_STATUS_SUCCESS << 16) | VMW_PORT_CMD_HB_MSG, |
|---|
| 215 | 218 | reply_len, si, di, |
|---|
| 216 | | - VMW_HYPERVISOR_HB_PORT | (channel->channel_id << 16), |
|---|
| 219 | + VMWARE_HYPERVISOR_HB | (channel->channel_id << 16), |
|---|
| 217 | 220 | VMW_HYPERVISOR_MAGIC, bp, |
|---|
| 218 | 221 | eax, ebx, ecx, edx, si, di); |
|---|
| 219 | 222 | |
|---|
| .. | .. |
|---|
| 230 | 233 | |
|---|
| 231 | 234 | VMW_PORT(VMW_PORT_CMD_MSG | (MSG_TYPE_RECVPAYLOAD << 16), |
|---|
| 232 | 235 | MESSAGE_STATUS_SUCCESS, si, di, |
|---|
| 233 | | - VMW_HYPERVISOR_PORT | (channel->channel_id << 16), |
|---|
| 236 | + channel->channel_id << 16, |
|---|
| 234 | 237 | VMW_HYPERVISOR_MAGIC, |
|---|
| 235 | 238 | eax, ebx, ecx, edx, si, di); |
|---|
| 236 | 239 | |
|---|
| .. | .. |
|---|
| 269 | 272 | |
|---|
| 270 | 273 | VMW_PORT(VMW_PORT_CMD_SENDSIZE, |
|---|
| 271 | 274 | msg_len, si, di, |
|---|
| 272 | | - VMW_HYPERVISOR_PORT | (channel->channel_id << 16), |
|---|
| 275 | + channel->channel_id << 16, |
|---|
| 273 | 276 | VMW_HYPERVISOR_MAGIC, |
|---|
| 274 | 277 | eax, ebx, ecx, edx, si, di); |
|---|
| 275 | 278 | |
|---|
| .. | .. |
|---|
| 327 | 330 | |
|---|
| 328 | 331 | VMW_PORT(VMW_PORT_CMD_RECVSIZE, |
|---|
| 329 | 332 | 0, si, di, |
|---|
| 330 | | - (VMW_HYPERVISOR_PORT | (channel->channel_id << 16)), |
|---|
| 333 | + channel->channel_id << 16, |
|---|
| 331 | 334 | VMW_HYPERVISOR_MAGIC, |
|---|
| 332 | 335 | eax, ebx, ecx, edx, si, di); |
|---|
| 333 | 336 | |
|---|
| .. | .. |
|---|
| 371 | 374 | |
|---|
| 372 | 375 | VMW_PORT(VMW_PORT_CMD_RECVSTATUS, |
|---|
| 373 | 376 | MESSAGE_STATUS_SUCCESS, si, di, |
|---|
| 374 | | - (VMW_HYPERVISOR_PORT | (channel->channel_id << 16)), |
|---|
| 377 | + channel->channel_id << 16, |
|---|
| 375 | 378 | VMW_HYPERVISOR_MAGIC, |
|---|
| 376 | 379 | eax, ebx, ecx, edx, si, di); |
|---|
| 377 | 380 | |
|---|
| .. | .. |
|---|
| 516 | 519 | |
|---|
| 517 | 520 | return -EINVAL; |
|---|
| 518 | 521 | } |
|---|
| 522 | + |
|---|
| 523 | + |
|---|
| 524 | +/** |
|---|
| 525 | + * vmw_msg_ioctl: Sends and receveives a message to/from host from/to user-space |
|---|
| 526 | + * |
|---|
| 527 | + * Sends a message from user-space to host. |
|---|
| 528 | + * Can also receive a result from host and return that to user-space. |
|---|
| 529 | + * |
|---|
| 530 | + * @dev: Identifies the drm device. |
|---|
| 531 | + * @data: Pointer to the ioctl argument. |
|---|
| 532 | + * @file_priv: Identifies the caller. |
|---|
| 533 | + * Return: Zero on success, negative error code on error. |
|---|
| 534 | + */ |
|---|
| 535 | + |
|---|
| 536 | +int vmw_msg_ioctl(struct drm_device *dev, void *data, |
|---|
| 537 | + struct drm_file *file_priv) |
|---|
| 538 | +{ |
|---|
| 539 | + struct drm_vmw_msg_arg *arg = |
|---|
| 540 | + (struct drm_vmw_msg_arg *) data; |
|---|
| 541 | + struct rpc_channel channel; |
|---|
| 542 | + char *msg; |
|---|
| 543 | + int length; |
|---|
| 544 | + |
|---|
| 545 | + msg = kmalloc(MAX_USER_MSG_LENGTH, GFP_KERNEL); |
|---|
| 546 | + if (!msg) { |
|---|
| 547 | + DRM_ERROR("Cannot allocate memory for log message.\n"); |
|---|
| 548 | + return -ENOMEM; |
|---|
| 549 | + } |
|---|
| 550 | + |
|---|
| 551 | + length = strncpy_from_user(msg, (void __user *)((unsigned long)arg->send), |
|---|
| 552 | + MAX_USER_MSG_LENGTH); |
|---|
| 553 | + if (length < 0 || length >= MAX_USER_MSG_LENGTH) { |
|---|
| 554 | + DRM_ERROR("Userspace message access failure.\n"); |
|---|
| 555 | + kfree(msg); |
|---|
| 556 | + return -EINVAL; |
|---|
| 557 | + } |
|---|
| 558 | + |
|---|
| 559 | + |
|---|
| 560 | + if (vmw_open_channel(&channel, RPCI_PROTOCOL_NUM)) { |
|---|
| 561 | + DRM_ERROR("Failed to open channel.\n"); |
|---|
| 562 | + goto out_open; |
|---|
| 563 | + } |
|---|
| 564 | + |
|---|
| 565 | + if (vmw_send_msg(&channel, msg)) { |
|---|
| 566 | + DRM_ERROR("Failed to send message to host.\n"); |
|---|
| 567 | + goto out_msg; |
|---|
| 568 | + } |
|---|
| 569 | + |
|---|
| 570 | + if (!arg->send_only) { |
|---|
| 571 | + char *reply = NULL; |
|---|
| 572 | + size_t reply_len = 0; |
|---|
| 573 | + |
|---|
| 574 | + if (vmw_recv_msg(&channel, (void *) &reply, &reply_len)) { |
|---|
| 575 | + DRM_ERROR("Failed to receive message from host.\n"); |
|---|
| 576 | + goto out_msg; |
|---|
| 577 | + } |
|---|
| 578 | + if (reply && reply_len > 0) { |
|---|
| 579 | + if (copy_to_user((void __user *)((unsigned long)arg->receive), |
|---|
| 580 | + reply, reply_len)) { |
|---|
| 581 | + DRM_ERROR("Failed to copy message to userspace.\n"); |
|---|
| 582 | + kfree(reply); |
|---|
| 583 | + goto out_msg; |
|---|
| 584 | + } |
|---|
| 585 | + arg->receive_len = (__u32)reply_len; |
|---|
| 586 | + } |
|---|
| 587 | + kfree(reply); |
|---|
| 588 | + } |
|---|
| 589 | + |
|---|
| 590 | + vmw_close_channel(&channel); |
|---|
| 591 | + kfree(msg); |
|---|
| 592 | + |
|---|
| 593 | + return 0; |
|---|
| 594 | + |
|---|
| 595 | +out_msg: |
|---|
| 596 | + vmw_close_channel(&channel); |
|---|
| 597 | +out_open: |
|---|
| 598 | + kfree(msg); |
|---|
| 599 | + |
|---|
| 600 | + return -EINVAL; |
|---|
| 601 | +} |
|---|