1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 06:47:35 +00:00

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.
This commit is contained in:
Jelle Raaijmakers 2021-11-04 15:34:26 +01:00 committed by Andreas Kling
parent 8a65a9c30f
commit a4b1c0fd0c
3 changed files with 30 additions and 19 deletions

View file

@ -27,20 +27,27 @@ UNMAP_AFTER_INIT RefPtr<VMWareMouseDevice> VMWareMouseDevice::try_to_initialize(
void VMWareMouseDevice::irq_handle_byte_read(u8) void VMWareMouseDevice::irq_handle_byte_read(u8)
{ {
VERIFY(VMWareBackdoor::the()); auto backdoor = VMWareBackdoor::the();
VERIFY(VMWareBackdoor::the()->vmmouse_is_absolute()); VERIFY(backdoor);
// We won't receive complete packets with the backdoor enabled, VERIFY(backdoor->vmmouse_is_absolute());
// 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 // We will receive 4 bytes from the I8042 controller that we are going to
// full PS/2 packet then we would create a backlog in the VM // ignore. Instead, we will check with VMWareBackdoor to see how many bytes
// because we wouldn't read the appropriate number of mouse // of mouse event data are waiting for us. For each multiple of 4, we
// packets from VMWareBackdoor. // produce a mouse packet.
auto mouse_packet = VMWareBackdoor::the()->receive_mouse_packet(); constexpr u8 max_iterations = 128;
if (mouse_packet.has_value()) { u8 current_iteration = 0;
m_entropy_source.add_random_event(mouse_packet.value()); 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); SpinlockLocker lock(m_queue_lock);
m_queue.enqueue(mouse_packet.value()); m_queue.enqueue(mouse_packet);
} }
evaluate_block_conditions(); evaluate_block_conditions();
} }

View file

@ -183,22 +183,26 @@ void VMWareBackdoor::send(VMWareCommand& command)
command.dx); command.dx);
} }
Optional<MousePacket> VMWareBackdoor::receive_mouse_packet() u16 VMWareBackdoor::read_mouse_status_queue_size()
{ {
VMWareCommand command; VMWareCommand command;
command.bx = 0; command.bx = 0;
command.command = VMMOUSE_STATUS; command.command = VMMOUSE_STATUS;
send(command); send(command);
if (command.ax == 0xFFFF0000) { if (command.ax == 0xFFFF0000) {
dbgln_if(PS2MOUSE_DEBUG, "PS2MouseDevice: Resetting VMWare mouse"); dbgln_if(PS2MOUSE_DEBUG, "PS2MouseDevice: Resetting VMWare mouse");
disable_absolute_vmmouse(); disable_absolute_vmmouse();
enable_absolute_vmmouse(); enable_absolute_vmmouse();
return {}; return 0;
} }
int words = command.ax & 0xFFFF;
if (!words || words % 4) return command.ax & 0xFFFF;
return {}; }
MousePacket VMWareBackdoor::receive_mouse_packet()
{
VMWareCommand command;
command.size = 4; command.size = 4;
command.command = VMMOUSE_DATA; command.command = VMMOUSE_DATA;
send(command); send(command);

View file

@ -6,7 +6,6 @@
#pragma once #pragma once
#include <AK/Optional.h>
#include <AK/Types.h> #include <AK/Types.h>
#include <AK/kmalloc.h> #include <AK/kmalloc.h>
#include <Kernel/API/MousePacket.h> #include <Kernel/API/MousePacket.h>
@ -51,7 +50,8 @@ public:
void disable_absolute_vmmouse(); void disable_absolute_vmmouse();
void send(VMWareCommand& command); void send(VMWareCommand& command);
Optional<MousePacket> receive_mouse_packet(); u16 read_mouse_status_queue_size();
MousePacket receive_mouse_packet();
private: private:
void send_high_bandwidth(VMWareCommand& command); void send_high_bandwidth(VMWareCommand& command);