On Sun, Aug 23, 2026 at 11:17 AM Christian Quante <[email protected]> wrote: > > ps2_write_mouse() ends its command switch with a bare "default: break;", > so an unknown command draws no reply at all. A real PS/2 device answers > every byte it is given -- ACK (0xFA) when it understood one, resend > (0xFE) when it did not -- and a guest that gets nothing back is left > waiting out its reply timeout. The keyboard path in the same file has > always answered unknown commands with KBD_REPLY_RESEND. > > Two guests were measured on this. > > OS/2 probes the mouse with the vendor command 0xBB, which QEMU does not > implement, and then polls the status port until its own timeout runs > out. On a Warp 3 guest that wait costs about 25 ms of every boot under > TCG, and 2.1 s under KVM, where each of those polls leaves the guest. > With this patch the wait ends on the first read: the guest takes the > same error path an unexpected reply would, and does not retry. > > Linux probes for a TrackPoint with 0xE1 and fails the same way. Timing > the psmouse detection from a mark written to /dev/kmsg to the kernel's > "input:" line, three boots each of a 6.18.35 kernel under TCG: > 426.7/428.8/441.6 ms without this patch, 21.4/21.6/21.2 ms with it. The > mouse is detected identically either way; libps2 caps its retries at > two attempts and ends in the same -EPROTO the timeout produced. > > The specification's second stage -- 0xFC (Error) when the byte after a > rejected one is invalid as well -- is deliberately left out. It would > need state that has to survive migration, no guest is known to test for > it, and the keyboard path has answered unknown commands with a bare > resend for twenty years. > > Signed-off-by: Christian Quante <[email protected]>
Reviewed-by: Marc-André Lureau <[email protected]> > --- > hw/input/ps2.c | 8 ++++++++ > 1 file changed, 8 insertions(+) > > diff --git a/hw/input/ps2.c b/hw/input/ps2.c > index 5516eb262d..1e8c6d983a 100644 > --- a/hw/input/ps2.c > +++ b/hw/input/ps2.c > @@ -73,6 +73,7 @@ > #define AUX_SET_DEFAULT 0xF6 > #define AUX_RESET 0xFF /* Reset aux device */ > #define AUX_ACK 0xFA /* Command byte ACK. */ > +#define AUX_RESEND 0xFE /* Command NACK, send the cmd again */ > > #define MOUSE_STATUS_REMOTE 0x40 > #define MOUSE_STATUS_ENABLED 0x20 > @@ -955,6 +956,13 @@ void ps2_write_mouse(PS2MouseState *s, int val) > s->mouse_type); > break; > default: > + /* > + * A PS/2 device answers every command it is given; an unknown > + * one draws a resend. Staying silent leaves the guest waiting > + * out its reply timeout. The keyboard path above answers > + * unknown commands with KBD_REPLY_RESEND. > + */ > + ps2_queue(ps2, AUX_RESEND); > break; > } > break; > -- > 2.53.0 > >
