summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJelle Raaijmakers <jelle@gmta.nl>2021-11-04 15:34:26 +0100
committerAndreas Kling <kling@serenityos.org>2021-11-04 18:53:37 +0100
commita4b1c0fd0cad4cdfa24d05c724b711fd9db6bda5 (patch)
tree765183be679d928b24550461f5c497164930bda3
parent8a65a9c30f7655fe27828d5eb1fdcf40d8fbe097 (diff)
downloadserenity-a4b1c0fd0cad4cdfa24d05c724b711fd9db6bda5.zip
Kernel: Process available VMWare mouse events immediately
The Qemu I8042 controller does not send one IRQ per event, it sends over four since it will not stop trying to emulate the PS/2 mouse. If the VMWare backdoor is active, a fake I8042 mouse event will be sent that we can then use to check if there are VMWare mouse events present. However, we were only processing one mouse event at a time, even though multiple events could have been queued up. Luckily this does not often lead to issues, since after the first IRQ we would still get three additional interrupts that would then empty the queue. This change makes sure we always empty the event queue immediately, instead of waiting on the next interrupt to happen. Functionally this changes nothing - it could merely improve latency by not waiting for new interrupts to come in. Coincidently, this brings our implementation closer to how Linux deals with the VMMouse.
-rw-r--r--Kernel/Devices/HID/VMWareMouseDevice.cpp31
-rw-r--r--Kernel/Devices/VMWareBackdoor.cpp14
-rw-r--r--Kernel/Devices/VMWareBackdoor.h4
3 files changed, 30 insertions, 19 deletions
diff --git a/Kernel/Devices/HID/VMWareMouseDevice.cpp b/Kernel/Devices/HID/VMWareMouseDevice.cpp
index e27cce4be2..1177be3007 100644
--- a/Kernel/Devices/HID/VMWareMouseDevice.cpp
+++ b/Kernel/Devices/HID/VMWareMouseDevice.cpp
@@ -27,20 +27,27 @@ UNMAP_AFTER_INIT RefPtr<VMWareMouseDevice> VMWareMouseDevice::try_to_initialize(
void VMWareMouseDevice::irq_handle_byte_read(u8)
{
- VERIFY(VMWareBackdoor::the());
- VERIFY(VMWareBackdoor::the()->vmmouse_is_absolute());
- // We won't receive complete packets with the backdoor enabled,
- // we will only get one byte for each event, which we'll just
- // discard. If we were to wait until we *think* that we got a
- // full PS/2 packet then we would create a backlog in the VM
- // because we wouldn't read the appropriate number of mouse
- // packets from VMWareBackdoor.
- auto mouse_packet = VMWareBackdoor::the()->receive_mouse_packet();
- if (mouse_packet.has_value()) {
- m_entropy_source.add_random_event(mouse_packet.value());
+ auto backdoor = VMWareBackdoor::the();
+ VERIFY(backdoor);
+ VERIFY(backdoor->vmmouse_is_absolute());
+
+ // We will receive 4 bytes from the I8042 controller that we are going to
+ // ignore. Instead, we will check with VMWareBackdoor to see how many bytes
+ // of mouse event data are waiting for us. For each multiple of 4, we
+ // produce a mouse packet.
+ constexpr u8 max_iterations = 128;
+ u8 current_iteration = 0;
+ while (++current_iteration < max_iterations) {
+ auto number_of_mouse_event_bytes = backdoor->read_mouse_status_queue_size();
+ if (number_of_mouse_event_bytes == 0)
+ break;
+ VERIFY(number_of_mouse_event_bytes % 4 == 0);
+
+ auto mouse_packet = backdoor->receive_mouse_packet();
+ m_entropy_source.add_random_event(mouse_packet);
{
SpinlockLocker lock(m_queue_lock);
- m_queue.enqueue(mouse_packet.value());
+ m_queue.enqueue(mouse_packet);
}
evaluate_block_conditions();
}
diff --git a/Kernel/Devices/VMWareBackdoor.cpp b/Kernel/Devices/VMWareBackdoor.cpp
index 1932bc5ecd..4d34eeef0c 100644
--- a/Kernel/Devices/VMWareBackdoor.cpp
+++ b/Kernel/Devices/VMWareBackdoor.cpp
@@ -183,22 +183,26 @@ void VMWareBackdoor::send(VMWareCommand& command)
command.dx);
}
-Optional<MousePacket> VMWareBackdoor::receive_mouse_packet()
+u16 VMWareBackdoor::read_mouse_status_queue_size()
{
VMWareCommand command;
command.bx = 0;
command.command = VMMOUSE_STATUS;
send(command);
+
if (command.ax == 0xFFFF0000) {
dbgln_if(PS2MOUSE_DEBUG, "PS2MouseDevice: Resetting VMWare mouse");
disable_absolute_vmmouse();
enable_absolute_vmmouse();
- return {};
+ return 0;
}
- int words = command.ax & 0xFFFF;
- if (!words || words % 4)
- return {};
+ return command.ax & 0xFFFF;
+}
+
+MousePacket VMWareBackdoor::receive_mouse_packet()
+{
+ VMWareCommand command;
command.size = 4;
command.command = VMMOUSE_DATA;
send(command);
diff --git a/Kernel/Devices/VMWareBackdoor.h b/Kernel/Devices/VMWareBackdoor.h
index c7a3d0db8f..c8fd80bf35 100644
--- a/Kernel/Devices/VMWareBackdoor.h
+++ b/Kernel/Devices/VMWareBackdoor.h
@@ -6,7 +6,6 @@
#pragma once
-#include <AK/Optional.h>
#include <AK/Types.h>
#include <AK/kmalloc.h>
#include <Kernel/API/MousePacket.h>
@@ -51,7 +50,8 @@ public:
void disable_absolute_vmmouse();
void send(VMWareCommand& command);
- Optional<MousePacket> receive_mouse_packet();
+ u16 read_mouse_status_queue_size();
+ MousePacket receive_mouse_packet();
private:
void send_high_bandwidth(VMWareCommand& command);