Index: trunk/src/VBox/Additions/common/VBoxVideo/HGSMIBase.cpp
===================================================================
--- trunk/src/VBox/Additions/common/VBoxVideo/HGSMIBase.cpp	(revision 60298)
+++ trunk/src/VBox/Additions/common/VBoxVideo/HGSMIBase.cpp	(revision 60300)
@@ -664,5 +664,5 @@
             if (pyHost)
                 *pyHost = p->y;
-            Log(("%s: return: x=%u, y=%u\n", __PRETTY_FUNCTION__, (unsigned)x, (unsigned)y));
+            Log(("%s: return: x=%u, y=%u\n", __PRETTY_FUNCTION__, (unsigned)p->x, (unsigned)p->y));
         }
         /* Free the IO buffer. */
Index: trunk/src/VBox/Additions/linux/drm/vbox_drv.h
===================================================================
--- trunk/src/VBox/Additions/linux/drm/vbox_drv.h	(revision 60298)
+++ trunk/src/VBox/Additions/linux/drm/vbox_drv.h	(revision 60300)
@@ -85,4 +85,6 @@
 #define VBOX_MAX_CURSOR_WIDTH  64
 #define VBOX_MAX_CURSOR_HEIGHT 64
+#define CURSOR_PIXEL_COUNT VBOX_MAX_CURSOR_WIDTH * VBOX_MAX_CURSOR_HEIGHT
+#define CURSOR_DATA_SIZE CURSOR_PIXEL_COUNT * 4 + CURSOR_PIXEL_COUNT / 8
 
 struct vbox_fbdev;
@@ -125,5 +127,14 @@
     uint32_t input_mapping_width;
     uint32_t input_mapping_height;
-};
+    uint32_t cursor_width;
+    uint32_t cursor_height;
+    uint32_t cursor_hot_x;
+    uint32_t cursor_hot_y;
+    size_t cursor_data_size;
+    uint8_t cursor_data[CURSOR_DATA_SIZE];
+};
+
+#undef CURSOR_PIXEL_COUNT
+#undef CURSOR_DATA_SIZE
 
 int vbox_driver_load(struct drm_device *dev, unsigned long flags);
Index: trunk/src/VBox/Additions/linux/drm/vbox_mode.c
===================================================================
--- trunk/src/VBox/Additions/linux/drm/vbox_mode.c	(revision 60298)
+++ trunk/src/VBox/Additions/linux/drm/vbox_mode.c	(revision 60300)
@@ -319,7 +319,5 @@
 static const struct drm_crtc_funcs vbox_crtc_funcs = {
     .cursor_move = vbox_cursor_move,
-#ifdef DRM_IOCTL_MODE_CURSOR2
     .cursor_set2 = vbox_cursor_set2,
-#endif
     .reset = vbox_crtc_reset,
     .set_config = drm_crtc_helper_set_config,
@@ -659,5 +657,5 @@
     vbox_crtc->cursor_enabled = true;
     if (   width > VBOX_MAX_CURSOR_WIDTH || height > VBOX_MAX_CURSOR_HEIGHT
-        || width == 0 || hot_x > width || height == 0 || hot_y > height)
+        || width == 0 || height == 0)
         return -EINVAL;
     rc = VBoxQueryConfHGSMI(&vbox->submit_info,
@@ -681,28 +679,33 @@
             mask_size  = ((width + 7) / 8 * height + 3) & ~3;
             data_size = width * height * 4 + mask_size;
-            dst = kmalloc(data_size, GFP_KERNEL);
-            if (dst)
+            vbox->cursor_hot_x = min((uint32_t)max(hot_x, 0), width);
+            vbox->cursor_hot_y = min((uint32_t)max(hot_y, 0), height);
+            vbox->cursor_width = width;
+            vbox->cursor_height = height;
+            vbox->cursor_data_size = data_size;
+            dst = vbox->cursor_data;
+            ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &uobj_map);
+            if (!ret)
             {
-                ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &uobj_map);
-                if (!ret)
+                src = ttm_kmap_obj_virtual(&uobj_map, &src_isiomem);
+                if (!src_isiomem)
                 {
-                    src = ttm_kmap_obj_virtual(&uobj_map, &src_isiomem);
-                    if (!src_isiomem)
-                    {
-                        uint32_t flags =   VBOX_MOUSE_POINTER_VISIBLE
-                                          | VBOX_MOUSE_POINTER_SHAPE
-                                          | VBOX_MOUSE_POINTER_ALPHA;
-                        copy_cursor_image(src, dst, width, height, mask_size);
-                        rc = VBoxHGSMIUpdatePointerShape(&vbox->submit_info, flags,
-                                                         hot_x, hot_y, width,
-                                                         height, dst, data_size);
-                        ret = -RTErrConvertToErrno(rc);
-                    }
-                    else
-                        DRM_ERROR("src cursor bo should be in main memory\n");
-                    ttm_bo_kunmap(&uobj_map);
+                    uint32_t flags =   VBOX_MOUSE_POINTER_VISIBLE
+                                      | VBOX_MOUSE_POINTER_SHAPE
+                                      | VBOX_MOUSE_POINTER_ALPHA;
+                    copy_cursor_image(src, dst, width, height, mask_size);
+                    rc = VBoxHGSMIUpdatePointerShape(&vbox->submit_info, flags,
+                                                     vbox->cursor_hot_x,
+                                                     vbox->cursor_hot_y,
+                                                     width, height, dst,
+                                                     data_size);
+                    ret = -RTErrConvertToErrno(rc);
                 }
-                kfree(dst);
+                else
+                    DRM_ERROR("src cursor bo should be in main memory\n");
+                ttm_bo_kunmap(&uobj_map);
             }
+            else
+                vbox->cursor_data_size = 0;
             vbox_bo_unreserve(bo);
         }
@@ -721,7 +724,31 @@
 {
     struct vbox_private *vbox = crtc->dev->dev_private;
-
-    VBoxHGSMICursorPosition(&vbox->submit_info, true, x + crtc->x,
-                            y + crtc->y, NULL, NULL);
-    return 0;
-}
+    uint32_t flags =   VBOX_MOUSE_POINTER_VISIBLE
+                      | VBOX_MOUSE_POINTER_SHAPE
+                      | VBOX_MOUSE_POINTER_ALPHA;
+    uint32_t host_x, host_y;
+    uint32_t hot_x = 0;
+    uint32_t hot_y = 0;
+    int rc;
+
+    /* We compare these to unsigned later and don't need to handle negative. */
+    if (x + crtc->x < 0 || y + crtc->y < 0 || vbox->cursor_data_size == 0)
+        return 0;
+    rc = VBoxHGSMICursorPosition(&vbox->submit_info, true, x + crtc->x,
+                                 y + crtc->y, &host_x, &host_y);
+    if (RT_FAILURE(rc))
+        return -RTErrConvertToErrno(rc);
+    if (x + crtc->x < host_x)
+        hot_x = min(host_x - x - crtc->x, vbox->cursor_width);
+    if (y + crtc->y < host_y)
+        hot_y = min(host_y - y - crtc->y, vbox->cursor_height);
+    if (hot_x == vbox->cursor_hot_x && hot_y == vbox->cursor_hot_y)
+        return 0;
+    vbox->cursor_hot_x = hot_x;
+    vbox->cursor_hot_y = hot_y;
+    rc = VBoxHGSMIUpdatePointerShape(&vbox->submit_info, flags, hot_x, hot_y,
+                                     vbox->cursor_width, vbox->cursor_height,
+                                     vbox->cursor_data,
+                                     vbox->cursor_data_size);
+    return -RTErrConvertToErrno(rc);
+}
