From af4eaf10978e5b14660020f39e619059489cc694 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Thu, 14 Nov 2019 13:03:18 +0000 Subject: [PATCH 01/10] drm/vmwgfx: Don't use the HB port if memory encryption is active With memory encryption active, the hypervisor typically can't read the guest memory using the HB port, since it is encrypted using a key known only to the guest. In that case fall back to processing 4 bytes at a time using the ordinary backdoor port. The other option would be to use unencrypted bounce buffers for the hypervisor to read out from or write into, but given the limited message sizes it appears more efficient to just fall back to the ordinary backdoor port. Signed-off-by: Thomas Hellstrom Reviewed-by: Roland Scheidegger --- drivers/gpu/drm/vmwgfx/vmwgfx_msg.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c b/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c index b6c5e4c2ac3c..d63441194249 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c @@ -28,6 +28,7 @@ #include #include #include +#include #include @@ -148,7 +149,8 @@ static unsigned long vmw_port_hb_out(struct rpc_channel *channel, unsigned long si, di, eax, ebx, ecx, edx; unsigned long msg_len = strlen(msg); - if (hb) { + /* HB port can't access encrypted memory. */ + if (hb && !mem_encrypt_active()) { unsigned long bp = channel->cookie_high; si = (uintptr_t) msg; @@ -202,7 +204,8 @@ static unsigned long vmw_port_hb_in(struct rpc_channel *channel, char *reply, { unsigned long si, di, eax, ebx, ecx, edx; - if (hb) { + /* HB port can't access encrypted memory */ + if (hb && !mem_encrypt_active()) { unsigned long bp = channel->cookie_low; si = channel->cookie_high; From 36891da8de9822a62d79b64f99e73442efbf3f1d Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Tue, 10 Dec 2019 13:43:22 +0100 Subject: [PATCH 02/10] drm/vmwgfx: Call vmw_driver_{load,unload}() before registering device The load/unload callbacks in struct drm_driver are deprecated. Remove them and call functions explicitly. Signed-off-by: Thomas Zimmermann Reviewed-by: Thomas Hellstrom Signed-off-by: Thomas Hellstrom --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 42 +++++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index e962048f65d2..dc3d04f00683 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -28,10 +28,10 @@ #include #include #include +#include #include #include -#include #include #include #include @@ -1211,8 +1211,10 @@ static void vmw_remove(struct pci_dev *pdev) { struct drm_device *dev = pci_get_drvdata(pdev); + drm_dev_unregister(dev); + vmw_driver_unload(dev); + drm_dev_put(dev); pci_disable_device(pdev); - drm_put_dev(dev); } static int vmwgfx_pm_notifier(struct notifier_block *nb, unsigned long val, @@ -1391,8 +1393,6 @@ static const struct file_operations vmwgfx_driver_fops = { static struct drm_driver driver = { .driver_features = DRIVER_MODESET | DRIVER_RENDER | DRIVER_ATOMIC, - .load = vmw_driver_load, - .unload = vmw_driver_unload, .get_vblank_counter = vmw_get_vblank_counter, .enable_vblank = vmw_enable_vblank, .disable_vblank = vmw_disable_vblank, @@ -1431,7 +1431,39 @@ static struct pci_driver vmw_pci_driver = { static int vmw_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { - return drm_get_pci_dev(pdev, ent, &driver); + struct drm_device *dev; + int ret; + + ret = pci_enable_device(pdev); + if (ret) + return ret; + + dev = drm_dev_alloc(&driver, &pdev->dev); + if (IS_ERR(dev)) { + ret = PTR_ERR(dev); + goto err_pci_disable_device; + } + + dev->pdev = pdev; + pci_set_drvdata(pdev, dev); + + ret = vmw_driver_load(dev, ent->driver_data); + if (ret) + goto err_drm_dev_put; + + ret = drm_dev_register(dev, ent->driver_data); + if (ret) + goto err_vmw_driver_unload; + + return 0; + +err_vmw_driver_unload: + vmw_driver_unload(dev); +err_drm_dev_put: + drm_dev_put(dev); +err_pci_disable_device: + pci_disable_device(pdev); + return ret; } static int __init vmwgfx_init(void) From a26ca967c240c628085142d6569fff69539b44e6 Mon Sep 17 00:00:00 2001 From: Lukas Bulwahn Date: Sun, 8 Dec 2019 11:53:28 +0100 Subject: [PATCH 03/10] drm/vmwgfx: Replace deprecated PTR_RET Commit 508108ea2747 ("drm/vmwgfx: Don't refcount command-buffer managed resource lookups during command buffer validation") slips in use of deprecated PTR_RET. Use PTR_ERR_OR_ZERO instead. As the PTR_ERR_OR_ZERO is a bit longer than PTR_RET, we introduce local variable ret for proper indentation and line-length limits. Signed-off-by: Lukas Bulwahn Reviewed-by: Thomas Hellstrom Signed-off-by: Thomas Hellstrom --- drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c index 934ad7c0c342..73489a45decb 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c @@ -2377,9 +2377,12 @@ static int vmw_cmd_dx_clear_rendertarget_view(struct vmw_private *dev_priv, { VMW_DECLARE_CMD_VAR(*cmd, SVGA3dCmdDXClearRenderTargetView) = container_of(header, typeof(*cmd), header); + struct vmw_resource *ret; - return PTR_RET(vmw_view_id_val_add(sw_context, vmw_view_rt, - cmd->body.renderTargetViewId)); + ret = vmw_view_id_val_add(sw_context, vmw_view_rt, + cmd->body.renderTargetViewId); + + return PTR_ERR_OR_ZERO(ret); } /** @@ -2396,9 +2399,12 @@ static int vmw_cmd_dx_clear_depthstencil_view(struct vmw_private *dev_priv, { VMW_DECLARE_CMD_VAR(*cmd, SVGA3dCmdDXClearDepthStencilView) = container_of(header, typeof(*cmd), header); + struct vmw_resource *ret; - return PTR_RET(vmw_view_id_val_add(sw_context, vmw_view_ds, - cmd->body.depthStencilViewId)); + ret = vmw_view_id_val_add(sw_context, vmw_view_ds, + cmd->body.depthStencilViewId); + + return PTR_ERR_OR_ZERO(ret); } static int vmw_cmd_dx_view_define(struct vmw_private *dev_priv, @@ -2741,9 +2747,12 @@ static int vmw_cmd_dx_genmips(struct vmw_private *dev_priv, { VMW_DECLARE_CMD_VAR(*cmd, SVGA3dCmdDXGenMips) = container_of(header, typeof(*cmd), header); + struct vmw_resource *ret; - return PTR_RET(vmw_view_id_val_add(sw_context, vmw_view_sr, - cmd->body.shaderResourceViewId)); + ret = vmw_view_id_val_add(sw_context, vmw_view_sr, + cmd->body.shaderResourceViewId); + + return PTR_ERR_OR_ZERO(ret); } /** From 8815a94f27d2f30fe1216ce10c7da0f6ae69ca0f Mon Sep 17 00:00:00 2001 From: Emil Velikov Date: Fri, 1 Nov 2019 13:03:09 +0000 Subject: [PATCH 04/10] drm/vmwgfx: move the require_exist handling together Move the render_client hunk for require_exist alongside the rest. Keeping all the reasons why an existing object is needed, in a single place makes it easier to follow. Cc: VMware Graphics Cc: Thomas Hellstrom Signed-off-by: Emil Velikov Reviewed-by: Thomas Hellstrom Signed-off-by: Thomas Hellstrom --- drivers/gpu/drm/vmwgfx/vmwgfx_surface.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c index 32b9131b2bae..590bde993946 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c @@ -934,16 +934,12 @@ vmw_surface_handle_reference(struct vmw_private *dev_priv, uint32_t handle; struct ttm_base_object *base; int ret; - bool require_exist = false; if (handle_type == DRM_VMW_HANDLE_PRIME) { ret = ttm_prime_fd_to_handle(tfile, u_handle, &handle); if (unlikely(ret != 0)) return ret; } else { - if (unlikely(drm_is_render_client(file_priv))) - require_exist = true; - handle = u_handle; } @@ -960,6 +956,8 @@ vmw_surface_handle_reference(struct vmw_private *dev_priv, } if (handle_type != DRM_VMW_HANDLE_PRIME) { + bool require_exist = false; + user_srf = container_of(base, struct vmw_user_surface, prime.base); @@ -971,6 +969,9 @@ vmw_surface_handle_reference(struct vmw_private *dev_priv, user_srf->master != file_priv->master) require_exist = true; + if (unlikely(drm_is_render_client(file_priv))) + require_exist = true; + ret = ttm_ref_object_add(tfile, base, TTM_REF_USAGE, NULL, require_exist); if (unlikely(ret != 0)) { From 4872e6aa217fbb475ffa0ad7bda0d9acff543f2c Mon Sep 17 00:00:00 2001 From: Emil Velikov Date: Fri, 1 Nov 2019 13:03:10 +0000 Subject: [PATCH 05/10] drm/vmwgfx: check master authentication in surface_ref ioctls With later commit we'll rework DRM authentication handling. Namely DRM_AUTH will not be a requirement for DRM_RENDER_ALLOW ioctls. Since vmwgfx does isolation for primary clients in different master realms, the DRM_AUTH can be dropped. The only place where authentication matters, is surface_reference ioctls whenever a legacy (non-prime) handle is used. For those ioctls we call vmw_surface_handle_reference(), where we explicitly check if the client is both a) master and b) unauthenticated - bailing out as result. Otherwise the usual isolation path kicks in and we're all good. v2: Reword commit message, since the isolation work has landed. Cc: VMware Graphics Cc: Thomas Hellstrom Signed-off-by: Emil Velikov Reviewed-by: Thomas Hellstrom Signed-off-by: Thomas Hellstrom --- drivers/gpu/drm/vmwgfx/vmwgfx_surface.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c index 590bde993946..3ce630aa4fde 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c @@ -961,6 +961,13 @@ vmw_surface_handle_reference(struct vmw_private *dev_priv, user_srf = container_of(base, struct vmw_user_surface, prime.base); + /* Error out if we are unauthenticated primary */ + if (drm_is_primary_client(file_priv) && + !file_priv->authenticated) { + ret = -EACCES; + goto out_bad_resource; + } + /* * Make sure the surface creator has the same * authenticating master, or is already registered with us. From 0d4c19f93812c7b71c3a15f27fc4c5b2d990b2e6 Mon Sep 17 00:00:00 2001 From: Emil Velikov Date: Fri, 1 Nov 2019 13:03:11 +0000 Subject: [PATCH 06/10] drm/vmwgfx: drop DRM_AUTH for render ioctls With earlier commit 9c84aeba67cc ("drm/vmwgfx: Kill unneeded legacy security features") we removed the no longer applicable validation, as we now have isolation of primary clients from different master realms. As of last commit, we're explicitly checking for authentication in the only render ioctls which care about one. With those in place, the DRM_AUTH token serves no real purpose. Let's drop it. Cc: VMware Graphics Cc: Thomas Hellstrom Signed-off-by: Emil Velikov Reviewed-by: Thomas Hellstrom Signed-off-by: Thomas Hellstrom --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index dc3d04f00683..bc3d85174ca0 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -165,9 +165,9 @@ static const struct drm_ioctl_desc vmw_ioctls[] = { VMW_IOCTL_DEF(VMW_GET_PARAM, vmw_getparam_ioctl, - DRM_AUTH | DRM_RENDER_ALLOW), + DRM_RENDER_ALLOW), VMW_IOCTL_DEF(VMW_ALLOC_DMABUF, vmw_bo_alloc_ioctl, - DRM_AUTH | DRM_RENDER_ALLOW), + DRM_RENDER_ALLOW), VMW_IOCTL_DEF(VMW_UNREF_DMABUF, vmw_bo_unref_ioctl, DRM_RENDER_ALLOW), VMW_IOCTL_DEF(VMW_CURSOR_BYPASS, @@ -182,16 +182,16 @@ static const struct drm_ioctl_desc vmw_ioctls[] = { DRM_MASTER), VMW_IOCTL_DEF(VMW_CREATE_CONTEXT, vmw_context_define_ioctl, - DRM_AUTH | DRM_RENDER_ALLOW), + DRM_RENDER_ALLOW), VMW_IOCTL_DEF(VMW_UNREF_CONTEXT, vmw_context_destroy_ioctl, DRM_RENDER_ALLOW), VMW_IOCTL_DEF(VMW_CREATE_SURFACE, vmw_surface_define_ioctl, - DRM_AUTH | DRM_RENDER_ALLOW), + DRM_RENDER_ALLOW), VMW_IOCTL_DEF(VMW_UNREF_SURFACE, vmw_surface_destroy_ioctl, DRM_RENDER_ALLOW), VMW_IOCTL_DEF(VMW_REF_SURFACE, vmw_surface_reference_ioctl, - DRM_AUTH | DRM_RENDER_ALLOW), - VMW_IOCTL_DEF(VMW_EXECBUF, vmw_execbuf_ioctl, DRM_AUTH | + DRM_RENDER_ALLOW), + VMW_IOCTL_DEF(VMW_EXECBUF, vmw_execbuf_ioctl, DRM_RENDER_ALLOW), VMW_IOCTL_DEF(VMW_FENCE_WAIT, vmw_fence_obj_wait_ioctl, DRM_RENDER_ALLOW), @@ -201,9 +201,9 @@ static const struct drm_ioctl_desc vmw_ioctls[] = { VMW_IOCTL_DEF(VMW_FENCE_UNREF, vmw_fence_obj_unref_ioctl, DRM_RENDER_ALLOW), VMW_IOCTL_DEF(VMW_FENCE_EVENT, vmw_fence_event_ioctl, - DRM_AUTH | DRM_RENDER_ALLOW), + DRM_RENDER_ALLOW), VMW_IOCTL_DEF(VMW_GET_3D_CAP, vmw_get_cap_3d_ioctl, - DRM_AUTH | DRM_RENDER_ALLOW), + DRM_RENDER_ALLOW), /* these allow direct access to the framebuffers mark as master only */ VMW_IOCTL_DEF(VMW_PRESENT, vmw_present_ioctl, @@ -221,28 +221,28 @@ static const struct drm_ioctl_desc vmw_ioctls[] = { DRM_RENDER_ALLOW), VMW_IOCTL_DEF(VMW_CREATE_SHADER, vmw_shader_define_ioctl, - DRM_AUTH | DRM_RENDER_ALLOW), + DRM_RENDER_ALLOW), VMW_IOCTL_DEF(VMW_UNREF_SHADER, vmw_shader_destroy_ioctl, DRM_RENDER_ALLOW), VMW_IOCTL_DEF(VMW_GB_SURFACE_CREATE, vmw_gb_surface_define_ioctl, - DRM_AUTH | DRM_RENDER_ALLOW), + DRM_RENDER_ALLOW), VMW_IOCTL_DEF(VMW_GB_SURFACE_REF, vmw_gb_surface_reference_ioctl, - DRM_AUTH | DRM_RENDER_ALLOW), + DRM_RENDER_ALLOW), VMW_IOCTL_DEF(VMW_SYNCCPU, vmw_user_bo_synccpu_ioctl, DRM_RENDER_ALLOW), VMW_IOCTL_DEF(VMW_CREATE_EXTENDED_CONTEXT, vmw_extended_context_define_ioctl, - DRM_AUTH | DRM_RENDER_ALLOW), + DRM_RENDER_ALLOW), VMW_IOCTL_DEF(VMW_GB_SURFACE_CREATE_EXT, vmw_gb_surface_define_ext_ioctl, - DRM_AUTH | DRM_RENDER_ALLOW), + DRM_RENDER_ALLOW), VMW_IOCTL_DEF(VMW_GB_SURFACE_REF_EXT, vmw_gb_surface_reference_ext_ioctl, - DRM_AUTH | DRM_RENDER_ALLOW), + DRM_RENDER_ALLOW), }; static const struct pci_device_id vmw_pci_id_list[] = { From 40efb09a7f53125719e49864da008495e39aaa1e Mon Sep 17 00:00:00 2001 From: Navid Emamdoost Date: Tue, 24 Sep 2019 23:37:58 -0500 Subject: [PATCH 07/10] drm/vmwgfx: prevent memory leak in vmw_cmdbuf_res_add In vmw_cmdbuf_res_add if drm_ht_insert_item fails the allocated memory for cres should be released. Fixes: 18e4a4669c50 ("drm/vmwgfx: Fix compat shader namespace") Signed-off-by: Navid Emamdoost Reviewed-by: Thomas Hellstrom Signed-off-by: Thomas Hellstrom --- drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf_res.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf_res.c b/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf_res.c index 4ac55fc2bf97..44d858ce4ce7 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf_res.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf_res.c @@ -209,8 +209,10 @@ int vmw_cmdbuf_res_add(struct vmw_cmdbuf_res_manager *man, cres->hash.key = user_key | (res_type << 24); ret = drm_ht_insert_item(&man->resources, &cres->hash); - if (unlikely(ret != 0)) + if (unlikely(ret != 0)) { + kfree(cres); goto out_invalid_key; + } cres->state = VMW_CMDBUF_RES_ADD; cres->res = vmw_resource_reference(res); From cb92a3235956442c5ff211291865e219dc4cf4a0 Mon Sep 17 00:00:00 2001 From: Roland Scheidegger Date: Thu, 21 Nov 2019 17:44:56 +0100 Subject: [PATCH 08/10] drm/vmwgfx: add ioctl for messaging from/to guest userspace to/from host Up to now, guest userspace does logging directly to host using essentially the same rather complex port assembly stuff as the kernel. We'd rather use the same mechanism than duplicate it (it may also change in the future), hence add a new ioctl for relaying guest/host messaging (logging is just one application of it). Signed-off-by: Roland Scheidegger Reviewed-by: Thomas Hellstrom Signed-off-by: Thomas Hellstrom --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 6 +++ drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 2 + drivers/gpu/drm/vmwgfx/vmwgfx_msg.c | 83 +++++++++++++++++++++++++++++ include/uapi/drm/vmwgfx_drm.h | 17 ++++++ 4 files changed, 108 insertions(+) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index bc3d85174ca0..827458f49112 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -150,6 +150,9 @@ #define DRM_IOCTL_VMW_GB_SURFACE_REF_EXT \ DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_GB_SURFACE_REF_EXT, \ union drm_vmw_gb_surface_reference_ext_arg) +#define DRM_IOCTL_VMW_MSG \ + DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_MSG, \ + struct drm_vmw_msg_arg) /** * The core DRM version of this macro doesn't account for @@ -243,6 +246,9 @@ static const struct drm_ioctl_desc vmw_ioctls[] = { VMW_IOCTL_DEF(VMW_GB_SURFACE_REF_EXT, vmw_gb_surface_reference_ext_ioctl, DRM_RENDER_ALLOW), + VMW_IOCTL_DEF(VMW_MSG, + vmw_msg_ioctl, + DRM_RENDER_ALLOW), }; static const struct pci_device_id vmw_pci_id_list[] = { diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index a31e726d6d71..bfcb12dbaac1 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -1403,6 +1403,8 @@ int vmw_bo_cpu_blit(struct ttm_buffer_object *dst, int vmw_host_get_guestinfo(const char *guest_info_param, char *buffer, size_t *length); int vmw_host_log(const char *log); +int vmw_msg_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); /* VMW logging */ diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c b/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c index d63441194249..e9f448a5ebb3 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c @@ -57,6 +57,8 @@ #define HIGH_WORD(X) ((X & 0xFFFF0000) >> 16) +#define MAX_USER_MSG_LENGTH PAGE_SIZE + static u32 vmw_msg_enabled = 1; enum rpc_msg_type { @@ -517,3 +519,84 @@ out_open: return -EINVAL; } + + +/** + * vmw_msg_ioctl: Sends and receveives a message to/from host from/to user-space + * + * Sends a message from user-space to host. + * Can also receive a result from host and return that to user-space. + * + * @dev: Identifies the drm device. + * @data: Pointer to the ioctl argument. + * @file_priv: Identifies the caller. + * Return: Zero on success, negative error code on error. + */ + +int vmw_msg_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_vmw_msg_arg *arg = + (struct drm_vmw_msg_arg *) data; + struct rpc_channel channel; + char *msg; + int length; + + msg = kmalloc(MAX_USER_MSG_LENGTH, GFP_KERNEL); + if (!msg) { + DRM_ERROR("Cannot allocate memory for log message.\n"); + return -ENOMEM; + } + + length = strncpy_from_user(msg, (void __user *)((unsigned long)arg->send), + MAX_USER_MSG_LENGTH); + if (length < 0 || length >= MAX_USER_MSG_LENGTH) { + DRM_ERROR("Userspace message access failure.\n"); + kfree(msg); + return -EINVAL; + } + + + if (vmw_open_channel(&channel, RPCI_PROTOCOL_NUM)) { + DRM_ERROR("Failed to open channel.\n"); + goto out_open; + } + + if (vmw_send_msg(&channel, msg)) { + DRM_ERROR("Failed to send message to host.\n"); + goto out_msg; + } + + if (!arg->send_only) { + char *reply = NULL; + size_t reply_len = 0; + + if (vmw_recv_msg(&channel, (void *) &reply, &reply_len)) { + DRM_ERROR("Failed to receive message from host.\n"); + goto out_msg; + } + if (reply && reply_len > 0) { + if (copy_to_user((void __user *)((unsigned long)arg->receive), + reply, reply_len)) { + DRM_ERROR("Failed to copy message to userspace.\n"); + kfree(reply); + goto out_msg; + } + arg->receive_len = (__u32)reply_len; + } + kfree(reply); + } + + vmw_close_channel(&channel); + kfree(msg); + + return 0; + +out_msg: + vmw_close_channel(&channel); +out_open: + kfree(msg); + + return -EINVAL; +} + diff --git a/include/uapi/drm/vmwgfx_drm.h b/include/uapi/drm/vmwgfx_drm.h index 02cab33f2f25..fcb741e3068f 100644 --- a/include/uapi/drm/vmwgfx_drm.h +++ b/include/uapi/drm/vmwgfx_drm.h @@ -71,6 +71,7 @@ extern "C" { #define DRM_VMW_CREATE_EXTENDED_CONTEXT 26 #define DRM_VMW_GB_SURFACE_CREATE_EXT 27 #define DRM_VMW_GB_SURFACE_REF_EXT 28 +#define DRM_VMW_MSG 29 /*************************************************************************/ /** @@ -1213,6 +1214,22 @@ union drm_vmw_gb_surface_reference_ext_arg { struct drm_vmw_surface_arg req; }; +/** + * struct drm_vmw_msg_arg + * + * @send: Pointer to user-space msg string (null terminated). + * @receive: Pointer to user-space receive buffer. + * @send_only: Boolean whether this is only sending or receiving too. + * + * Argument to the DRM_VMW_MSG ioctl. + */ +struct drm_vmw_msg_arg { + __u64 send; + __u64 receive; + __s32 send_only; + __u32 receive_len; +}; + #if defined(__cplusplus) } #endif From 61780dd7a45e72d697e35b675ca71e75b6ab08ce Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 14 Jan 2020 11:38:19 +0100 Subject: [PATCH 09/10] drm/vmwgfx: Bump driver minor version Bump driver minor version to signal availability of the host messaging ioctl. Signed-off-by: Thomas Hellstrom Reviewed-by: Charmaine Lee Reviewed-by: Roland Scheidegger --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index bfcb12dbaac1..86b69397d166 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -56,9 +56,9 @@ #define VMWGFX_DRIVER_NAME "vmwgfx" -#define VMWGFX_DRIVER_DATE "20190328" +#define VMWGFX_DRIVER_DATE "20200114" #define VMWGFX_DRIVER_MAJOR 2 -#define VMWGFX_DRIVER_MINOR 16 +#define VMWGFX_DRIVER_MINOR 17 #define VMWGFX_DRIVER_PATCHLEVEL 0 #define VMWGFX_FIFO_STATIC_SIZE (1024*1024) #define VMWGFX_MAX_RELOCATIONS 2048 From b20414252068263c736d008e536658f9ce13d74a Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 4 Dec 2019 11:42:15 +0100 Subject: [PATCH 10/10] drm/vmwgfx: Use VM_PFNMAP instead of VM_MIXEDMAP when possible For shared, and read-only private mappings of graphics memory, use VM_PFNMAP instead of VM_MIXEDMAP. This means less accounting overhead when inserting and removing page-table entries. TTM doesn't do this by default, since there was a performance problem with book-keeping of write-combined mappings. Since vmwgfx solely uses cached mappings, that's not a problem and now that the TTM vm has largely been turned into helpers, we can use VM_PFNMAP on a per-driver basis Signed-off-by: Thomas Hellstrom Reviewed-by: Roland Scheidegger --- drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c index ce288756531b..aa7e50f63b94 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c @@ -45,6 +45,10 @@ int vmw_mmap(struct file *filp, struct vm_area_struct *vma) vma->vm_ops = &vmw_vm_ops; + /* Use VM_PFNMAP rather than VM_MIXEDMAP if not a COW mapping */ + if ((vma->vm_flags & (VM_SHARED | VM_MAYWRITE)) != VM_MAYWRITE) + vma->vm_flags = (vma->vm_flags & ~VM_MIXEDMAP) | VM_PFNMAP; + return 0; }