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::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 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 #include #include #include @@ -51,7 +50,8 @@ public: void disable_absolute_vmmouse(); void send(VMWareCommand& command); - Optional receive_mouse_packet(); + u16 read_mouse_status_queue_size(); + MousePacket receive_mouse_packet(); private: void send_high_bandwidth(VMWareCommand& command);