From nobody Tue Feb 10 00:40:51 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1621078675; cv=none; d=zohomail.com; s=zohoarc; b=K4mwollrM3yKR7mAnPHjojBqL3GF0aXRIOG3sKIo3dJBxli2X+CoNMNYkBmf7C5scR9WKq2B3AAqqCpJQKjqVzhZROnm1NyoV419BDhTGUyXDNbhoBlGzDjfuBz6ipWd23X3Wh6ssjma2NpxlZL9Tio1k9KTw/vnOZKvNjbWWOc= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1621078675; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=SzlsouvxfxtpKXtXEAhMYeahJis17VjFc+3Y3JlvnaY=; b=NB2LG1Y3KfabHvy8iitd+dNfh51t4WCSkAUmz90T95bqSkvJcZFY2QeWck5yhwGpfOXJSOYPKwzpxM5MZoe37pXM/WjRbWApEXvqQ/LCFtpUB2x7urPcOwxsauRgRps9Ocfi0aRv5evOIhZSBhv3RRN9Rrro0bnVHIz6flbydgc= ARC-Authentication-Results: i=1; mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1621078675829650.4309504404002; Sat, 15 May 2021 04:37:55 -0700 (PDT) Received: from localhost ([::1]:56178 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lhscE-00084g-3o for importer@patchew.org; Sat, 15 May 2021 07:37:54 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:46428) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lhsXi-0003wy-1u for qemu-devel@nongnu.org; Sat, 15 May 2021 07:33:14 -0400 Received: from mailout05.t-online.de ([194.25.134.82]:50314) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lhsXf-0003LG-CH for qemu-devel@nongnu.org; Sat, 15 May 2021 07:33:13 -0400 Received: from fwd21.aul.t-online.de (fwd21.aul.t-online.de [172.20.27.66]) by mailout05.t-online.de (Postfix) with SMTP id B5440641C1; Sat, 15 May 2021 13:33:09 +0200 (CEST) Received: from linpower.localnet (SyOrCuZpohhCJKHtTskqERfZlEOVtsahOaTAemR83o8H-pHU+Z5c1uowQ0NR+jHwmG@[79.208.18.63]) by fwd21.t-online.de with (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384 encrypted) esmtp id 1lhsXZ-0No6XA0; Sat, 15 May 2021 13:33:05 +0200 Received: by linpower.localnet (Postfix, from userid 1000) id AABEC200627; Sat, 15 May 2021 13:32:54 +0200 (CEST) From: =?UTF-8?q?Volker=20R=C3=BCmelin?= To: "Michael S. Tsirkin" , Paolo Bonzini , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Subject: [PATCH v3 05/11] pckbd: don't update OBF flags if KBD_STAT_OBF is set Date: Sat, 15 May 2021 13:32:48 +0200 Message-Id: <20210515113254.6245-5-vr_qemu@t-online.de> X-Mailer: git-send-email 2.26.2 In-Reply-To: References: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-ID: SyOrCuZpohhCJKHtTskqERfZlEOVtsahOaTAemR83o8H-pHU+Z5c1uowQ0NR+jHwmG X-TOI-EXPURGATEID: 150726::1621078385-00002A54-43E4D81A/0/0 CLEAN NORMAL X-TOI-MSGID: b5e258ef-2432-491d-a055-f49fdd9fca21 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: none client-ip=194.25.134.82; envelope-from=volker.ruemelin@t-online.de; helo=mailout05.t-online.de X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_NONE=0.001, SPF_NONE=0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: qemu-devel@nongnu.org Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Don't update the OBF flags in the status register and the cor- responding IRQ lines if KBD_STAT_OBF is set. Otherwise this may change the PS/2 event type. If the guest ISR was already scheduled, the changed event type will be rather surprising for the guest. This fixes a mouse event stream corruption. To reproduce the problem start a FreeDOS 1.2 guest with -machine pc,accel=3Dkvm and -display gtk. The KVM in-kernel irqchip has to be enabled. Now open a text file with edit.exe in the guest and hold down the cursor right key and at the same time move the mouse around. You will quickly notice erratic mouse movements and unexpected mouse clicks. A trace file shows the mouse event stream corruption. Guest rip 0xce93 (f000:ce93) is the in al,0x60 instruction in the seabios mouse ISR, guest rip 0xceca (f000:ceca) is the in al,0x60 instruction in the seabios keyboard ISR. qemu-system-x86-5659 [007] .... 280.971116: tracing_mark_write: pckbd_kbd_update_irq kbd=3D0 aux=3D1 # gtk queues a mouse event qemu-system-x86-5665 [000] .... 280.971121: kvm_exit: reason EXTERNAL_INTERRUPT rip 0x22da info 0 800000fd qemu-system-x86-5665 [000] d..1 280.971122: kvm_entry: vcpu 0, rip 0x22da qemu-system-x86-5665 [000] .... 280.971123: kvm_exit: reason EXTERNAL_INTERRUPT rip 0x22da info 0 800000fd qemu-system-x86-5665 [000] d..1 280.971124: kvm_entry: vcpu 0, rip 0x22da qemu-system-x86-5665 [000] .... 280.971126: kvm_exit: reason IO_INSTRUCTION rip 0x110c8c info 640008 0 qemu-system-x86-5665 [000] .... 280.971176: tracing_mark_write: pckbd_kbd_read_status 0x3d # KBD_STAT_OBF and KBD_STAT_MOUSE_OBF set, the mouse ISR will # read data from the PS/2 controller. qemu-system-x86-5665 [000] d..1 280.971180: kvm_entry: vcpu 0, rip 0x110c8d qemu-system-x86-5665 [000] .... 280.971191: kvm_exit: reason EXTERNAL_INTERRUPT rip 0x110c8d info 0 800000f6 qemu-system-x86-5665 [000] d..1 280.971191: kvm_entry: vcpu 0, rip 0x110c8d qemu-system-x86-5665 [000] .... 280.971193: kvm_exit: reason IO_INSTRUCTION rip 0xce93 info 600048 0 # the mouse ISR wants to read data from the PS/2 controller qemu-system-x86-5659 [007] .... 280.971231: tracing_mark_write: pckbd_kbd_update_irq kbd=3D1 aux=3D0 qemu-system-x86-5659 [007] .... 280.971238: tracing_mark_write: pckbd_kbd_update_irq kbd=3D1 aux=3D0 # gtk queues a keyboard event 0xe0 0x4d (key right) qemu-system-x86-5665 [000] .... 280.971257: tracing_mark_write: pckbd_kbd_update_irq kbd=3D0 aux=3D1 qemu-system-x86-5665 [000] .... 280.971262: tracing_mark_write: pckbd_kbd_update_irq kbd=3D1 aux=3D0 # ps2_read_data() deasserts and reasserts the keyboard IRQ qemu-system-x86-5665 [000] .... 280.971266: tracing_mark_write: pckbd_kbd_read_data 0xe0 kbd # -> the mouse ISR receives keyboard data qemu-system-x86-5665 [000] d..1 280.971268: kvm_entry: vcpu 0, rip 0xce95 qemu-system-x86-5665 [000] .... 280.971269: kvm_exit: reason IO_INSTRUCTION rip 0xe828 info a00040 0 qemu-system-x86-5665 [000] .... 280.971270: kvm_ack_irq: irqchip PIC slave pin 12 qemu-system-x86-5665 [000] d..1 280.971270: kvm_entry: vcpu 0, rip 0xe82a qemu-system-x86-5665 [000] .... 280.971271: kvm_exit: reason IO_INSTRUCTION rip 0xe82a info 200040 0 qemu-system-x86-5665 [000] .... 280.971271: kvm_ack_irq: irqchip PIC master pin 2 qemu-system-x86-5665 [000] d..1 280.971271: kvm_entry: vcpu 0, rip 0xe82c qemu-system-x86-5665 [000] .... 280.971272: kvm_exit: reason PENDING_INTERRUPT rip 0x22da info 0 0 qemu-system-x86-5665 [000] d..1 280.971273: kvm_entry: vcpu 0, rip 0x22da qemu-system-x86-5665 [000] .... 280.971274: kvm_exit: reason IO_INSTRUCTION rip 0x110c8c info 640008 0 qemu-system-x86-5665 [000] .... 280.971275: tracing_mark_write: pckbd_kbd_read_status 0x1d qemu-system-x86-5665 [000] d..1 280.971276: kvm_entry: vcpu 0, rip 0x110c8d qemu-system-x86-5665 [000] .... 280.971277: kvm_exit: reason IO_INSTRUCTION rip 0xceca info 600048 0 # the keyboard ISR wants to read data from the PS/2 controller qemu-system-x86-5665 [000] .... 280.971279: tracing_mark_write: pckbd_kbd_update_irq kbd=3D0 aux=3D1 qemu-system-x86-5665 [000] .... 280.971282: tracing_mark_write: pckbd_kbd_read_data 0x4d kbd # the keyboard ISR receives the second byte of the keyboard event Signed-off-by: Volker R=C3=BCmelin --- hw/input/pckbd.c | 91 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 68 insertions(+), 23 deletions(-) diff --git a/hw/input/pckbd.c b/hw/input/pckbd.c index 90b33954a8..8336f4e4b3 100644 --- a/hw/input/pckbd.c +++ b/hw/input/pckbd.c @@ -139,6 +139,7 @@ typedef struct KBDState { bool outport_present; /* Bitmask of devices with data available. */ uint8_t pending; + uint8_t obdata; void *kbd; void *mouse; =20 @@ -173,6 +174,13 @@ static void kbd_update_irq_lines(KBDState *s) qemu_set_irq(s->irq_mouse, irq_mouse_level); } =20 +static void kbd_deassert_irq(KBDState *s) +{ + s->status &=3D ~(KBD_STAT_OBF | KBD_STAT_MOUSE_OBF); + s->outport &=3D ~(KBD_OUT_OBF | KBD_OUT_MOUSE_OBF); + kbd_update_irq_lines(s); +} + /* update irq and KBD_STAT_[MOUSE_]OBF */ static void kbd_update_irq(KBDState *s) { @@ -181,7 +189,6 @@ static void kbd_update_irq(KBDState *s) if (s->pending) { s->status |=3D KBD_STAT_OBF; s->outport |=3D KBD_OUT_OBF; - /* kbd data takes priority over aux data. */ if (s->pending =3D=3D KBD_PENDING_AUX) { s->status |=3D KBD_STAT_MOUSE_OBF; s->outport |=3D KBD_OUT_MOUSE_OBF; @@ -190,26 +197,42 @@ static void kbd_update_irq(KBDState *s) kbd_update_irq_lines(s); } =20 +static void kbd_safe_update_irq(KBDState *s) +{ + /* + * with KBD_STAT_OBF set, a call to kbd_read_data() will eventually ca= ll + * kbd_update_irq() + */ + if (s->status & KBD_STAT_OBF) { + return; + } + if (s->pending) { + kbd_update_irq(s); + } +} + static void kbd_update_kbd_irq(void *opaque, int level) { - KBDState *s =3D (KBDState *)opaque; + KBDState *s =3D opaque; =20 - if (level) + if (level) { s->pending |=3D KBD_PENDING_KBD; - else + } else { s->pending &=3D ~KBD_PENDING_KBD; - kbd_update_irq(s); + } + kbd_safe_update_irq(s); } =20 static void kbd_update_aux_irq(void *opaque, int level) { - KBDState *s =3D (KBDState *)opaque; + KBDState *s =3D opaque; =20 - if (level) + if (level) { s->pending |=3D KBD_PENDING_AUX; - else + } else { s->pending &=3D ~KBD_PENDING_AUX; - kbd_update_irq(s); + } + kbd_safe_update_irq(s); } =20 static uint64_t kbd_read_status(void *opaque, hwaddr addr, @@ -290,11 +313,10 @@ static void kbd_write_command(void *opaque, hwaddr ad= dr, break; case KBD_CCMD_KBD_DISABLE: s->mode |=3D KBD_MODE_DISABLE_KBD; - kbd_update_irq(s); break; case KBD_CCMD_KBD_ENABLE: s->mode &=3D ~KBD_MODE_DISABLE_KBD; - kbd_update_irq(s); + kbd_safe_update_irq(s); break; case KBD_CCMD_READ_INPORT: kbd_queue(s, 0x80, 0); @@ -327,15 +349,19 @@ static uint64_t kbd_read_data(void *opaque, hwaddr ad= dr, unsigned size) { KBDState *s =3D opaque; - uint32_t val; + uint8_t status =3D s->status; =20 - if (s->pending =3D=3D KBD_PENDING_AUX) - val =3D ps2_read_data(s->mouse); - else - val =3D ps2_read_data(s->kbd); + if (status & KBD_STAT_OBF) { + kbd_deassert_irq(s); + if (status & KBD_STAT_MOUSE_OBF) { + s->obdata =3D ps2_read_data(s->mouse); + } else { + s->obdata =3D ps2_read_data(s->kbd); + } + } =20 - trace_pckbd_kbd_read_data(val); - return val; + trace_pckbd_kbd_read_data(s->obdata); + return s->obdata; } =20 static void kbd_write_data(void *opaque, hwaddr addr, @@ -352,8 +378,16 @@ static void kbd_write_data(void *opaque, hwaddr addr, case KBD_CCMD_WRITE_MODE: s->mode =3D val; ps2_keyboard_set_translation(s->kbd, (s->mode & KBD_MODE_KCC) !=3D= 0); - /* ??? */ - kbd_update_irq(s); + /* + * a write to the mode byte interrupt enable flags directly updates + * the irq lines + */ + kbd_update_irq_lines(s); + /* + * a write to the mode byte disable interface flags may raise + * an irq if there is pending data in the PS/2 queues. + */ + kbd_safe_update_irq(s); break; case KBD_CCMD_WRITE_OBUF: kbd_queue(s, val, 0); @@ -381,6 +415,8 @@ static void kbd_reset(void *opaque) s->status =3D KBD_STAT_CMD | KBD_STAT_UNLOCKED; s->outport =3D KBD_OUT_RESET | KBD_OUT_A20 | KBD_OUT_ONES; s->outport_present =3D false; + s->pending =3D 0; + kbd_deassert_irq(s); } =20 static uint8_t kbd_outport_default(KBDState *s) @@ -427,7 +463,7 @@ static int kbd_post_load(void *opaque, int version_id) =20 static const VMStateDescription vmstate_kbd =3D { .name =3D "pckbd", - .version_id =3D 3, + .version_id =3D 4, .minimum_version_id =3D 3, .post_load =3D kbd_post_load, .fields =3D (VMStateField[]) { @@ -435,6 +471,7 @@ static const VMStateDescription vmstate_kbd =3D { VMSTATE_UINT8(status, KBDState), VMSTATE_UINT8(mode, KBDState), VMSTATE_UINT8(pending, KBDState), + VMSTATE_UINT8_V(obdata, KBDState, 4), VMSTATE_END_OF_LIST() }, .subsections =3D (const VMStateDescription*[]) { @@ -512,12 +549,20 @@ void i8042_setup_a20_line(ISADevice *dev, qemu_irq a2= 0_out) qdev_connect_gpio_out_named(DEVICE(dev), I8042_A20_LINE, 0, a20_out); } =20 +static bool vmstate_version_id_3(void *opaque, int version_id) +{ + return version_id =3D=3D 3; +} + static const VMStateDescription vmstate_kbd_isa =3D { .name =3D "pckbd", - .version_id =3D 3, + .version_id =3D 4, .minimum_version_id =3D 3, .fields =3D (VMStateField[]) { - VMSTATE_STRUCT(kbd, ISAKBDState, 0, vmstate_kbd, KBDState), + VMSTATE_VSTRUCT_TEST(kbd, ISAKBDState, vmstate_version_id_3, + 3, vmstate_kbd, KBDState, 3), + VMSTATE_VSTRUCT_TEST(kbd, ISAKBDState, NULL, + 4, vmstate_kbd, KBDState, 4), VMSTATE_END_OF_LIST() } }; --=20 2.26.2