diff options
Diffstat (limited to '0002-virt-vbox-Add-support-for-the-new-VBG_IOCTL_ACQUIRE_.patch')
-rw-r--r-- | 0002-virt-vbox-Add-support-for-the-new-VBG_IOCTL_ACQUIRE_.patch | 689 |
1 files changed, 689 insertions, 0 deletions
diff --git a/0002-virt-vbox-Add-support-for-the-new-VBG_IOCTL_ACQUIRE_.patch b/0002-virt-vbox-Add-support-for-the-new-VBG_IOCTL_ACQUIRE_.patch new file mode 100644 index 0000000..ce36e01 --- /dev/null +++ b/0002-virt-vbox-Add-support-for-the-new-VBG_IOCTL_ACQUIRE_.patch @@ -0,0 +1,689 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jan Alexander Steffens (heftig)" <heftig@archlinux.org> +Date: Wed, 15 Jul 2020 22:42:07 +0200 +Subject: [PATCH] virt: vbox: Add support for the new + VBG_IOCTL_ACQUIRE_GUEST_CAPABILITIES ioctl + +https://lore.kernel.org/patchwork/cover/1270301/ + +Needed for https://bugs.archlinux.org/task/67253 + +Squashed commit of the following: + +commit 0d7bec556896815f4920a5ed87339732c697175c +Author: Hans de Goede <hdegoede@redhat.com> +Date: Thu Jul 9 14:08:58 2020 +0200 + + virt: vbox: Fix some comments which talk about the "session spinlock" + + The session lock is a mutex, not a spinlock, fix the comments to match. + + Acked-by: Arnd Bergmann <arnd@arndb.de> + Signed-off-by: Hans de Goede <hdegoede@redhat.com> + +commit fed91350029e0c3bf626bd55a148e766587ec439 +Author: Hans de Goede <hdegoede@redhat.com> +Date: Thu Jul 9 14:08:57 2020 +0200 + + virt: vbox: Log unknown ioctl requests as error + + Every now and then upstream adds new ioctls without notifying us, + log unknown ioctl requests as an error to catch these. + + Acked-by: Arnd Bergmann <arnd@arndb.de> + Signed-off-by: Hans de Goede <hdegoede@redhat.com> + +commit 245d06f4c1b8f84cde07d14c09296a4fe90a26f0 +Author: Hans de Goede <hdegoede@redhat.com> +Date: Thu Jul 9 14:08:56 2020 +0200 + + virt: vbox: Add a few new vmmdev request types to the userspace whitelist + + Upstream VirtualBox has defined and is using a few new request types for + vmmdev requests passed through /dev/vboxguest to the hypervisor. + + Add the defines for these to vbox_vmmdev_types.h and add add them to the + whitelists of vmmdev requests which userspace is allowed to make. + + BugLink: https://bugzilla.redhat.com/show_bug.cgi?id=1789545 + Acked-by: Arnd Bergmann <arnd@arndb.de> + Signed-off-by: Hans de Goede <hdegoede@redhat.com> + +commit 2f24f5446915322bbbb1ccf4ee2297512feab942 +Author: Hans de Goede <hdegoede@redhat.com> +Date: Thu Jul 9 14:08:55 2020 +0200 + + virt: vbox: Add support for the new VBG_IOCTL_ACQUIRE_GUEST_CAPABILITIES ioctl + + Add support for the new VBG_IOCTL_ACQUIRE_GUEST_CAPABILITIES ioctl, this + is necessary for automatic resizing of the guest resolution to match the + VM-window size to work with the new VMSVGA virtual GPU which is now the + new default in VirtualBox. + + BugLink: https://bugzilla.redhat.com/show_bug.cgi?id=1789545 + Acked-by: Arnd Bergmann <arnd@arndb.de> + Signed-off-by: Hans de Goede <hdegoede@redhat.com> + +commit 2fc9822453e8dd215765cd2b28e5e6e26338829e +Author: Hans de Goede <hdegoede@redhat.com> +Date: Thu Jul 9 14:08:54 2020 +0200 + + virt: vbox: Add vbg_set_host_capabilities() helper function + + Add vbg_set_host_capabilities() helper function, this is a preparation + patch for adding support for the VBGL_IOCTL_GUEST_CAPS_ACQUIRE ioctl. + + Acked-by: Arnd Bergmann <arnd@arndb.de> + Signed-off-by: Hans de Goede <hdegoede@redhat.com> + +commit 1594daf929c8691849c00e49e4a1ed977048addc +Author: Hans de Goede <hdegoede@redhat.com> +Date: Thu Jul 9 14:08:53 2020 +0200 + + virt: vbox: Rename guest_caps struct members to set_guest_caps + + Rename guest_caps[_tracker] struct members to set_guest_caps[_tracker] + this is a preparation patch for adding support for the + VBGL_IOCTL_GUEST_CAPS_ACQUIRE ioctl. + + Acked-by: Arnd Bergmann <arnd@arndb.de> + Signed-off-by: Hans de Goede <hdegoede@redhat.com> + +commit d7f3b7cec66d171cf5194ad37f647f4562da6ccc +Author: Hans de Goede <hdegoede@redhat.com> +Date: Thu Jul 9 14:08:52 2020 +0200 + + virt: vbox: Fix guest capabilities mask check + + Check the passed in capabilities against VMMDEV_GUEST_CAPABILITIES_MASK + instead of against VMMDEV_EVENT_VALID_EVENT_MASK. + This tightens the allowed mask from 0x7ff to 0x7. + + Fixes: 0ba002bc4393 ("virt: Add vboxguest driver for Virtual Box Guest integration") + Cc: stable@vger.kernel.org + Acked-by: Arnd Bergmann <arnd@arndb.de> + Signed-off-by: Hans de Goede <hdegoede@redhat.com> + +commit f6694fa90e2183874def2d022d097795e2269a15 +Author: Hans de Goede <hdegoede@redhat.com> +Date: Thu Jul 9 14:08:51 2020 +0200 + + virt: vbox: Fix VBGL_IOCTL_VMMDEV_REQUEST_BIG and _LOG req numbers to match upstream + + Until this commit the mainline kernel version (this version) of the + vboxguest module contained a bug where it defined + VBGL_IOCTL_VMMDEV_REQUEST_BIG and VBGL_IOCTL_LOG using + _IOC(_IOC_READ | _IOC_WRITE, 'V', ...) instead of + _IO(V, ...) as the out of tree VirtualBox upstream version does. + + Since the VirtualBox userspace bits are always built against VirtualBox + upstream's headers, this means that so far the mainline kernel version + of the vboxguest module has been failing these 2 ioctls with -ENOTTY. + I guess that VBGL_IOCTL_VMMDEV_REQUEST_BIG is never used causing us to + not hit that one and sofar the vboxguest driver has failed to actually + log any log messages passed it through VBGL_IOCTL_LOG. + + This commit changes the VBGL_IOCTL_VMMDEV_REQUEST_BIG and VBGL_IOCTL_LOG + defines to match the out of tree VirtualBox upstream vboxguest version, + while keeping compatibility with the old wrong request defines so as + to not break the kernel ABI in case someone has been using the old + request defines. + + Fixes: f6ddd094f579 ("virt: Add vboxguest driver for Virtual Box Guest integration UAPI") + Cc: stable@vger.kernel.org + Acked-by: Arnd Bergmann <arnd@arndb.de> + Reviewed-by: Arnd Bergmann <arnd@arndb.de> + Signed-off-by: Hans de Goede <hdegoede@redhat.com> +--- + drivers/virt/vboxguest/vboxguest_core.c | 266 +++++++++++++++++++---- + drivers/virt/vboxguest/vboxguest_core.h | 23 +- + drivers/virt/vboxguest/vboxguest_utils.c | 1 + + include/linux/vbox_utils.h | 1 + + include/uapi/linux/vbox_vmmdev_types.h | 3 + + include/uapi/linux/vboxguest.h | 24 ++ + 6 files changed, 269 insertions(+), 49 deletions(-) + +diff --git a/drivers/virt/vboxguest/vboxguest_core.c b/drivers/virt/vboxguest/vboxguest_core.c +index 95bfdb8ac8a2..f449fc366cf3 100644 +--- a/drivers/virt/vboxguest/vboxguest_core.c ++++ b/drivers/virt/vboxguest/vboxguest_core.c +@@ -558,7 +558,7 @@ static int vbg_reset_host_event_filter(struct vbg_dev *gdev, + * Changes the event filter mask for the given session. + * + * This is called in response to VBG_IOCTL_CHANGE_FILTER_MASK as well as to +- * do session cleanup. Takes the session spinlock. ++ * do session cleanup. Takes the session mutex. + * + * Return: 0 or negative errno value. + * @gdev: The Guest extension device. +@@ -661,78 +661,205 @@ static int vbg_reset_host_capabilities(struct vbg_dev *gdev) + } + + /** +- * Sets the guest capabilities for a session. Takes the session spinlock. ++ * Set guest capabilities on the host. ++ * Must be called with gdev->session_mutex hold. ++ * Return: 0 or negative errno value. ++ * @gdev: The Guest extension device. ++ * @session: The session. ++ * @session_termination: Set if we're called by the session cleanup code. ++ */ ++static int vbg_set_host_capabilities(struct vbg_dev *gdev, ++ struct vbg_session *session, ++ bool session_termination) ++{ ++ struct vmmdev_mask *req; ++ u32 caps; ++ int rc; ++ ++ WARN_ON(!mutex_is_locked(&gdev->session_mutex)); ++ ++ caps = gdev->acquired_guest_caps | gdev->set_guest_caps_tracker.mask; ++ ++ if (gdev->guest_caps_host == caps) ++ return 0; ++ ++ /* On termination the requestor is the kernel, as we're cleaning up. */ ++ req = vbg_req_alloc(sizeof(*req), VMMDEVREQ_SET_GUEST_CAPABILITIES, ++ session_termination ? VBG_KERNEL_REQUEST : ++ session->requestor); ++ if (!req) { ++ gdev->guest_caps_host = U32_MAX; ++ return -ENOMEM; ++ } ++ ++ req->or_mask = caps; ++ req->not_mask = ~caps; ++ rc = vbg_req_perform(gdev, req); ++ vbg_req_free(req, sizeof(*req)); ++ ++ gdev->guest_caps_host = (rc >= 0) ? caps : U32_MAX; ++ ++ return vbg_status_code_to_errno(rc); ++} ++ ++/** ++ * Acquire (get exclusive access) guest capabilities for a session. ++ * Takes the session mutex. ++ * Return: 0 or negative errno value. ++ * @gdev: The Guest extension device. ++ * @session: The session. ++ * @flags: Flags (VBGL_IOC_AGC_FLAGS_XXX). ++ * @or_mask: The capabilities to add. ++ * @not_mask: The capabilities to remove. ++ * @session_termination: Set if we're called by the session cleanup code. ++ * This tweaks the error handling so we perform ++ * proper session cleanup even if the host ++ * misbehaves. ++ */ ++static int vbg_acquire_session_capabilities(struct vbg_dev *gdev, ++ struct vbg_session *session, ++ u32 or_mask, u32 not_mask, ++ u32 flags, bool session_termination) ++{ ++ unsigned long irqflags; ++ bool wakeup = false; ++ int ret = 0; ++ ++ mutex_lock(&gdev->session_mutex); ++ ++ if (gdev->set_guest_caps_tracker.mask & or_mask) { ++ vbg_err("%s error: cannot acquire caps which are currently set\n", ++ __func__); ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ /* ++ * Mark any caps in the or_mask as now being in acquire-mode. Note ++ * once caps are in acquire_mode they always stay in this mode. ++ * This impacts event handling, so we take the event-lock. ++ */ ++ spin_lock_irqsave(&gdev->event_spinlock, irqflags); ++ gdev->acquire_mode_guest_caps |= or_mask; ++ spin_unlock_irqrestore(&gdev->event_spinlock, irqflags); ++ ++ /* If we only have to switch the caps to acquire mode, we're done. */ ++ if (flags & VBGL_IOC_AGC_FLAGS_CONFIG_ACQUIRE_MODE) ++ goto out; ++ ++ not_mask &= ~or_mask; /* or_mask takes priority over not_mask */ ++ not_mask &= session->acquired_guest_caps; ++ or_mask &= ~session->acquired_guest_caps; ++ ++ if (or_mask == 0 && not_mask == 0) ++ goto out; ++ ++ if (gdev->acquired_guest_caps & or_mask) { ++ ret = -EBUSY; ++ goto out; ++ } ++ ++ gdev->acquired_guest_caps |= or_mask; ++ gdev->acquired_guest_caps &= ~not_mask; ++ /* session->acquired_guest_caps impacts event handling, take the lock */ ++ spin_lock_irqsave(&gdev->event_spinlock, irqflags); ++ session->acquired_guest_caps |= or_mask; ++ session->acquired_guest_caps &= ~not_mask; ++ spin_unlock_irqrestore(&gdev->event_spinlock, irqflags); ++ ++ ret = vbg_set_host_capabilities(gdev, session, session_termination); ++ /* Roll back on failure, unless it's session termination time. */ ++ if (ret < 0 && !session_termination) { ++ gdev->acquired_guest_caps &= ~or_mask; ++ gdev->acquired_guest_caps |= not_mask; ++ spin_lock_irqsave(&gdev->event_spinlock, irqflags); ++ session->acquired_guest_caps &= ~or_mask; ++ session->acquired_guest_caps |= not_mask; ++ spin_unlock_irqrestore(&gdev->event_spinlock, irqflags); ++ } ++ ++ /* ++ * If we added a capability, check if that means some other thread in ++ * our session should be unblocked because there are events pending ++ * (the result of vbg_get_allowed_event_mask_for_session() may change). ++ * ++ * HACK ALERT! When the seamless support capability is added we generate ++ * a seamless change event so that the ring-3 client can sync with ++ * the seamless state. ++ */ ++ if (ret == 0 && or_mask != 0) { ++ spin_lock_irqsave(&gdev->event_spinlock, irqflags); ++ ++ if (or_mask & VMMDEV_GUEST_SUPPORTS_SEAMLESS) ++ gdev->pending_events |= ++ VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST; ++ ++ if (gdev->pending_events) ++ wakeup = true; ++ ++ spin_unlock_irqrestore(&gdev->event_spinlock, irqflags); ++ ++ if (wakeup) ++ wake_up(&gdev->event_wq); ++ } ++ ++out: ++ mutex_unlock(&gdev->session_mutex); ++ ++ return ret; ++} ++ ++/** ++ * Sets the guest capabilities for a session. Takes the session mutex. + * Return: 0 or negative errno value. + * @gdev: The Guest extension device. + * @session: The session. + * @or_mask: The capabilities to add. + * @not_mask: The capabilities to remove. + * @session_termination: Set if we're called by the session cleanup code. + * This tweaks the error handling so we perform + * proper session cleanup even if the host + * misbehaves. + */ + static int vbg_set_session_capabilities(struct vbg_dev *gdev, + struct vbg_session *session, + u32 or_mask, u32 not_mask, + bool session_termination) + { +- struct vmmdev_mask *req; + u32 changed, previous; +- int rc, ret = 0; +- +- /* +- * Allocate a request buffer before taking the spinlock, when +- * the session is being terminated the requestor is the kernel, +- * as we're cleaning up. +- */ +- req = vbg_req_alloc(sizeof(*req), VMMDEVREQ_SET_GUEST_CAPABILITIES, +- session_termination ? VBG_KERNEL_REQUEST : +- session->requestor); +- if (!req) { +- if (!session_termination) +- return -ENOMEM; +- /* Ignore allocation failure, we must do session cleanup. */ +- } ++ int ret = 0; + + mutex_lock(&gdev->session_mutex); + ++ if (gdev->acquire_mode_guest_caps & or_mask) { ++ vbg_err("%s error: cannot set caps which are in acquire_mode\n", ++ __func__); ++ ret = -EBUSY; ++ goto out; ++ } ++ + /* Apply the changes to the session mask. */ +- previous = session->guest_caps; +- session->guest_caps |= or_mask; +- session->guest_caps &= ~not_mask; ++ previous = session->set_guest_caps; ++ session->set_guest_caps |= or_mask; ++ session->set_guest_caps &= ~not_mask; + + /* If anything actually changed, update the global usage counters. */ +- changed = previous ^ session->guest_caps; ++ changed = previous ^ session->set_guest_caps; + if (!changed) + goto out; + +- vbg_track_bit_usage(&gdev->guest_caps_tracker, changed, previous); +- or_mask = gdev->guest_caps_tracker.mask; ++ vbg_track_bit_usage(&gdev->set_guest_caps_tracker, changed, previous); + +- if (gdev->guest_caps_host == or_mask || !req) +- goto out; +- +- gdev->guest_caps_host = or_mask; +- req->or_mask = or_mask; +- req->not_mask = ~or_mask; +- rc = vbg_req_perform(gdev, req); +- if (rc < 0) { +- ret = vbg_status_code_to_errno(rc); +- +- /* Failed, roll back (unless it's session termination time). */ +- gdev->guest_caps_host = U32_MAX; +- if (session_termination) +- goto out; +- +- vbg_track_bit_usage(&gdev->guest_caps_tracker, changed, +- session->guest_caps); +- session->guest_caps = previous; ++ ret = vbg_set_host_capabilities(gdev, session, session_termination); ++ /* Roll back on failure, unless it's session termination time. */ ++ if (ret < 0 && !session_termination) { ++ vbg_track_bit_usage(&gdev->set_guest_caps_tracker, changed, ++ session->set_guest_caps); ++ session->set_guest_caps = previous; + } + + out: + mutex_unlock(&gdev->session_mutex); +- vbg_req_free(req, sizeof(*req)); + + return ret; + } +@@ -948,6 +1075,7 @@ void vbg_core_close_session(struct vbg_session *session) + struct vbg_dev *gdev = session->gdev; + int i, rc; + ++ vbg_acquire_session_capabilities(gdev, session, 0, U32_MAX, 0, true); + vbg_set_session_capabilities(gdev, session, 0, U32_MAX, true); + vbg_set_session_event_filter(gdev, session, 0, U32_MAX, true); + +@@ -1005,31 +1133,52 @@ static int vbg_ioctl_driver_version_info( + return 0; + } + ++/* Must be called with the event_lock held */ ++static u32 vbg_get_allowed_event_mask_for_session(struct vbg_dev *gdev, ++ struct vbg_session *session) ++{ ++ u32 acquire_mode_caps = gdev->acquire_mode_guest_caps; ++ u32 session_acquired_caps = session->acquired_guest_caps; ++ u32 allowed_events = VMMDEV_EVENT_VALID_EVENT_MASK; ++ ++ if ((acquire_mode_caps & VMMDEV_GUEST_SUPPORTS_GRAPHICS) && ++ !(session_acquired_caps & VMMDEV_GUEST_SUPPORTS_GRAPHICS)) ++ allowed_events &= ~VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST; ++ ++ if ((acquire_mode_caps & VMMDEV_GUEST_SUPPORTS_SEAMLESS) && ++ !(session_acquired_caps & VMMDEV_GUEST_SUPPORTS_SEAMLESS)) ++ allowed_events &= ~VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST; ++ ++ return allowed_events; ++} ++ + static bool vbg_wait_event_cond(struct vbg_dev *gdev, + struct vbg_session *session, + u32 event_mask) + { + unsigned long flags; + bool wakeup; + u32 events; + + spin_lock_irqsave(&gdev->event_spinlock, flags); + + events = gdev->pending_events & event_mask; ++ events &= vbg_get_allowed_event_mask_for_session(gdev, session); + wakeup = events || session->cancel_waiters; + + spin_unlock_irqrestore(&gdev->event_spinlock, flags); + + return wakeup; + } + + /* Must be called with the event_lock held */ + static u32 vbg_consume_events_locked(struct vbg_dev *gdev, + struct vbg_session *session, + u32 event_mask) + { + u32 events = gdev->pending_events & event_mask; + ++ events &= vbg_get_allowed_event_mask_for_session(gdev, session); + gdev->pending_events &= ~events; + return events; + } +@@ -1149,7 +1298,9 @@ static int vbg_req_allowed(struct vbg_dev *gdev, struct vbg_session *session, + case VMMDEVREQ_VIDEO_ACCEL_ENABLE: + case VMMDEVREQ_VIDEO_ACCEL_FLUSH: + case VMMDEVREQ_VIDEO_SET_VISIBLE_REGION: ++ case VMMDEVREQ_VIDEO_UPDATE_MONITOR_POSITIONS: + case VMMDEVREQ_GET_DISPLAY_CHANGE_REQEX: ++ case VMMDEVREQ_GET_DISPLAY_CHANGE_REQ_MULTI: + case VMMDEVREQ_GET_SEAMLESS_CHANGE_REQ: + case VMMDEVREQ_GET_VRDPCHANGE_REQ: + case VMMDEVREQ_LOG_STRING: +@@ -1431,27 +1582,50 @@ static int vbg_ioctl_change_filter_mask(struct vbg_dev *gdev, + false); + } + ++static int vbg_ioctl_acquire_guest_capabilities(struct vbg_dev *gdev, ++ struct vbg_session *session, ++ struct vbg_ioctl_acquire_guest_caps *caps) ++{ ++ u32 flags, or_mask, not_mask; ++ ++ if (vbg_ioctl_chk(&caps->hdr, sizeof(caps->u.in), 0)) ++ return -EINVAL; ++ ++ flags = caps->u.in.flags; ++ or_mask = caps->u.in.or_mask; ++ not_mask = caps->u.in.not_mask; ++ ++ if (flags & ~VBGL_IOC_AGC_FLAGS_VALID_MASK) ++ return -EINVAL; ++ ++ if ((or_mask | not_mask) & ~VMMDEV_GUEST_CAPABILITIES_MASK) ++ return -EINVAL; ++ ++ return vbg_acquire_session_capabilities(gdev, session, or_mask, ++ not_mask, flags, false); ++} ++ + static int vbg_ioctl_change_guest_capabilities(struct vbg_dev *gdev, + struct vbg_session *session, struct vbg_ioctl_set_guest_caps *caps) + { + u32 or_mask, not_mask; + int ret; + + if (vbg_ioctl_chk(&caps->hdr, sizeof(caps->u.in), sizeof(caps->u.out))) + return -EINVAL; + + or_mask = caps->u.in.or_mask; + not_mask = caps->u.in.not_mask; + + if ((or_mask | not_mask) & ~VMMDEV_GUEST_CAPABILITIES_MASK) + return -EINVAL; + + ret = vbg_set_session_capabilities(gdev, session, or_mask, not_mask, + false); + if (ret) + return ret; + +- caps->u.out.session_caps = session->guest_caps; ++ caps->u.out.session_caps = session->set_guest_caps; + caps->u.out.global_caps = gdev->guest_caps_host; + + return 0; +@@ -1540,29 +1714,31 @@ int vbg_core_ioctl(struct vbg_session *session, unsigned int req, void *data) + return vbg_ioctl_interrupt_all_wait_events(gdev, session, data); + case VBG_IOCTL_CHANGE_FILTER_MASK: + return vbg_ioctl_change_filter_mask(gdev, session, data); ++ case VBG_IOCTL_ACQUIRE_GUEST_CAPABILITIES: ++ return vbg_ioctl_acquire_guest_capabilities(gdev, session, data); + case VBG_IOCTL_CHANGE_GUEST_CAPABILITIES: + return vbg_ioctl_change_guest_capabilities(gdev, session, data); + case VBG_IOCTL_CHECK_BALLOON: + return vbg_ioctl_check_balloon(gdev, data); + case VBG_IOCTL_WRITE_CORE_DUMP: + return vbg_ioctl_write_core_dump(gdev, session, data); + } + + /* Variable sized requests. */ + switch (req_no_size) { + #ifdef CONFIG_COMPAT + case VBG_IOCTL_HGCM_CALL_32(0): + f32bit = true; + #endif + /* Fall through */ + case VBG_IOCTL_HGCM_CALL(0): + return vbg_ioctl_hgcm_call(gdev, session, f32bit, data); + case VBG_IOCTL_LOG(0): + case VBG_IOCTL_LOG_ALT(0): + return vbg_ioctl_log(data); + } + +- vbg_debug("VGDrvCommonIoCtl: Unknown req %#08x\n", req); ++ vbg_err_ratelimited("Userspace made an unknown ioctl req %#08x\n", req); + return -ENOTTY; + } + +diff --git a/drivers/virt/vboxguest/vboxguest_core.h b/drivers/virt/vboxguest/vboxguest_core.h +index 77c3a9c8255d..ab4bf64e2cec 100644 +--- a/drivers/virt/vboxguest/vboxguest_core.h ++++ b/drivers/virt/vboxguest/vboxguest_core.h +@@ -118,11 +118,21 @@ struct vbg_dev { + u32 event_filter_host; + + /** +- * Usage counters for guest capabilities. Indexed by capability bit ++ * Guest capabilities which have been switched to acquire_mode. ++ */ ++ u32 acquire_mode_guest_caps; ++ /** ++ * Guest capabilities acquired by vbg_acquire_session_capabilities(). ++ * Only one session can acquire a capability at a time. ++ */ ++ u32 acquired_guest_caps; ++ /** ++ * Usage counters for guest capabilities requested through ++ * vbg_set_session_capabilities(). Indexed by capability bit + * number, one count per session using a capability. + * Protected by session_mutex. + */ +- struct vbg_bit_usage_tracker guest_caps_tracker; ++ struct vbg_bit_usage_tracker set_guest_caps_tracker; + /** + * The guest capabilities last reported to the host (or UINT32_MAX). + * Protected by session_mutex. +@@ -164,11 +174,16 @@ struct vbg_session { + */ + u32 event_filter; + /** +- * Guest capabilities for this session. ++ * Guest capabilities acquired by vbg_acquire_session_capabilities(). ++ * Only one session can acquire a capability at a time. ++ */ ++ u32 acquired_guest_caps; ++ /** ++ * Guest capabilities set through vbg_set_session_capabilities(). + * A capability claimed by any guest session will be reported to the + * host. Protected by vbg_gdev.session_mutex. + */ +- u32 guest_caps; ++ u32 set_guest_caps; + /** VMMDEV_REQUESTOR_* flags */ + u32 requestor; + /** Set on CANCEL_ALL_WAITEVENTS, protected by vbg_devevent_spinlock. */ +diff --git a/drivers/virt/vboxguest/vboxguest_utils.c b/drivers/virt/vboxguest/vboxguest_utils.c +index 43c391626a00..b6fd06eb015e 100644 +--- a/drivers/virt/vboxguest/vboxguest_utils.c ++++ b/drivers/virt/vboxguest/vboxguest_utils.c +@@ -58,6 +58,7 @@ EXPORT_SYMBOL(name) + VBG_LOG(vbg_info, pr_info); + VBG_LOG(vbg_warn, pr_warn); + VBG_LOG(vbg_err, pr_err); ++VBG_LOG(vbg_err_ratelimited, pr_err_ratelimited); + #if defined(DEBUG) && !defined(CONFIG_DYNAMIC_DEBUG) + VBG_LOG(vbg_debug, pr_debug); + #endif +diff --git a/include/linux/vbox_utils.h b/include/linux/vbox_utils.h +index ff56c443180c..db8a7d118093 100644 +--- a/include/linux/vbox_utils.h ++++ b/include/linux/vbox_utils.h +@@ -16,6 +16,7 @@ struct vbg_dev; + __printf(1, 2) void vbg_info(const char *fmt, ...); + __printf(1, 2) void vbg_warn(const char *fmt, ...); + __printf(1, 2) void vbg_err(const char *fmt, ...); ++__printf(1, 2) void vbg_err_ratelimited(const char *fmt, ...); + + /* Only use backdoor logging for non-dynamic debug builds */ + #if defined(DEBUG) && !defined(CONFIG_DYNAMIC_DEBUG) +diff --git a/include/uapi/linux/vbox_vmmdev_types.h b/include/uapi/linux/vbox_vmmdev_types.h +index c27289fd619a..f8a8d6b3c521 100644 +--- a/include/uapi/linux/vbox_vmmdev_types.h ++++ b/include/uapi/linux/vbox_vmmdev_types.h +@@ -63,6 +63,7 @@ enum vmmdev_request_type { + VMMDEVREQ_SET_GUEST_CAPABILITIES = 56, + VMMDEVREQ_VIDEMODE_SUPPORTED2 = 57, /* since version 3.2.0 */ + VMMDEVREQ_GET_DISPLAY_CHANGE_REQEX = 80, /* since version 4.2.4 */ ++ VMMDEVREQ_GET_DISPLAY_CHANGE_REQ_MULTI = 81, + VMMDEVREQ_HGCM_CONNECT = 60, + VMMDEVREQ_HGCM_DISCONNECT = 61, + VMMDEVREQ_HGCM_CALL32 = 62, +@@ -92,6 +93,8 @@ enum vmmdev_request_type { + VMMDEVREQ_WRITE_COREDUMP = 218, + VMMDEVREQ_GUEST_HEARTBEAT = 219, + VMMDEVREQ_HEARTBEAT_CONFIGURE = 220, ++ VMMDEVREQ_NT_BUG_CHECK = 221, ++ VMMDEVREQ_VIDEO_UPDATE_MONITOR_POSITIONS = 222, + /* Ensure the enum is a 32 bit data-type */ + VMMDEVREQ_SIZEHACK = 0x7fffffff + }; +diff --git a/include/uapi/linux/vboxguest.h b/include/uapi/linux/vboxguest.h +index f79d7abe27db..15125f6ec60d 100644 +--- a/include/uapi/linux/vboxguest.h ++++ b/include/uapi/linux/vboxguest.h +@@ -257,6 +257,30 @@ VMMDEV_ASSERT_SIZE(vbg_ioctl_change_filter, 24 + 8); + _IOWR('V', 12, struct vbg_ioctl_change_filter) + + ++/** VBG_IOCTL_ACQUIRE_GUEST_CAPABILITIES data structure. */ ++struct vbg_ioctl_acquire_guest_caps { ++ /** The header. */ ++ struct vbg_ioctl_hdr hdr; ++ union { ++ struct { ++ /** Flags (VBGL_IOC_AGC_FLAGS_XXX). */ ++ __u32 flags; ++ /** Capabilities to set (VMMDEV_GUEST_SUPPORTS_XXX). */ ++ __u32 or_mask; ++ /** Capabilities to drop (VMMDEV_GUEST_SUPPORTS_XXX). */ ++ __u32 not_mask; ++ } in; ++ } u; ++}; ++VMMDEV_ASSERT_SIZE(vbg_ioctl_acquire_guest_caps, 24 + 12); ++ ++#define VBGL_IOC_AGC_FLAGS_CONFIG_ACQUIRE_MODE 0x00000001 ++#define VBGL_IOC_AGC_FLAGS_VALID_MASK 0x00000001 ++ ++#define VBG_IOCTL_ACQUIRE_GUEST_CAPABILITIES \ ++ _IOWR('V', 13, struct vbg_ioctl_acquire_guest_caps) ++ ++ + /** VBG_IOCTL_CHANGE_GUEST_CAPABILITIES data structure. */ + struct vbg_ioctl_set_guest_caps { + /** The header. */ |