From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.7 required=3.0 tests=BAYES_00, FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS, URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 525CFC433B4 for ; Wed, 5 May 2021 19:29:05 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id DC318613C3 for ; Wed, 5 May 2021 19:29:04 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org DC318613C3 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=t-online.de Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:35682 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1leNCh-0007KI-U5 for qemu-devel@archiver.kernel.org; Wed, 05 May 2021 15:29:03 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:43638) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1leN6k-00021A-9I for qemu-devel@nongnu.org; Wed, 05 May 2021 15:22:54 -0400 Received: from mailout10.t-online.de ([194.25.134.21]:50388) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1leN6f-0007f0-3n for qemu-devel@nongnu.org; Wed, 05 May 2021 15:22:54 -0400 Received: from fwd12.aul.t-online.de (fwd12.aul.t-online.de [172.20.26.241]) by mailout10.t-online.de (Postfix) with SMTP id 19ECD9D70B; Wed, 5 May 2021 21:21:55 +0200 (CEST) Received: from linpower.localnet (JbrxvUZTZhaE+CgioCsmK2Lwv9cFw9wvRB+Cl09D+VtBNXhDwv+z6PP-ysf+SHHZdy@[46.86.52.8]) by fwd12.t-online.de with (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384 encrypted) esmtp id 1leN5f-0pmy5g0; Wed, 5 May 2021 21:21:47 +0200 Received: by linpower.localnet (Postfix, from userid 1000) id F24BB2006F4; Wed, 5 May 2021 21:21:33 +0200 (CEST) From: =?UTF-8?q?Volker=20R=C3=BCmelin?= To: "Michael S. Tsirkin" , Paolo Bonzini Subject: [PATCH 06/10] pckbd: PS/2 keyboard throttle Date: Wed, 5 May 2021 21:21:29 +0200 Message-Id: <20210505192133.7480-6-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: 8bit X-ID: JbrxvUZTZhaE+CgioCsmK2Lwv9cFw9wvRB+Cl09D+VtBNXhDwv+z6PP-ysf+SHHZdy X-TOI-EXPURGATEID: 150726::1620242507-00003D17-AB3461E4/0/0 CLEAN NORMAL X-TOI-MSGID: b86a769e-fc3c-40a9-a03e-ea6e94f16d0b Received-SPF: none client-ip=194.25.134.21; envelope-from=volker.ruemelin@t-online.de; helo=mailout10.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_H4=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+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" Limit the keyboard data rate to the serial link speed. Some old DOS software relies on being able to read an incoming scan-code more than once. After reading keyboard data from the i8042 controller, the guest software has 1ms to read the same data again. Use -global i8042.kbd-throttle=on to enable this feature. To see how this patch works, start a FreeDOS 1.2 guest with the qemu option -global i8042.kbd-throttle=on and open a text file with the vim 7.3 32 bit for DOS executable. Then use the cursor keys (not the cursor keys on the numeric keypad) to move through the text. Without the kbd-throttle option enabled each keystroke will move the cursor two positions. Buglink: https://bugs.launchpad.net/bugs/1895363 Buglink: https://bugs.launchpad.net/bugs/1897568 Signed-off-by: Volker RĂ¼melin --- hw/input/pckbd.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/hw/input/pckbd.c b/hw/input/pckbd.c index 8336f4e4b3..f45aebb6b8 100644 --- a/hw/input/pckbd.c +++ b/hw/input/pckbd.c @@ -24,12 +24,14 @@ #include "qemu/osdep.h" #include "qemu/log.h" +#include "qemu/timer.h" #include "hw/isa/isa.h" #include "migration/vmstate.h" #include "hw/acpi/aml-build.h" #include "hw/input/ps2.h" #include "hw/irq.h" #include "hw/input/i8042.h" +#include "hw/qdev-properties.h" #include "sysemu/reset.h" #include "sysemu/runstate.h" @@ -131,17 +133,21 @@ #define KBD_PENDING_KBD 1 #define KBD_PENDING_AUX 2 +#define KBD_MIGR_TIMER_PENDING 0x1 + typedef struct KBDState { uint8_t write_cmd; /* if non zero, write data to port 60 is expected */ uint8_t status; uint8_t mode; uint8_t outport; + uint32_t migration_flags; bool outport_present; /* Bitmask of devices with data available. */ uint8_t pending; uint8_t obdata; void *kbd; void *mouse; + QEMUTimer *throttle_timer; qemu_irq irq_kbd; qemu_irq irq_mouse; @@ -206,6 +212,10 @@ static void kbd_safe_update_irq(KBDState *s) if (s->status & KBD_STAT_OBF) { return; } + /* the throttle timer is pending and will call kbd_update_irq() */ + if (s->throttle_timer && timer_pending(s->throttle_timer)) { + return; + } if (s->pending) { kbd_update_irq(s); } @@ -235,6 +245,18 @@ static void kbd_update_aux_irq(void *opaque, int level) kbd_safe_update_irq(s); } +static void kbd_throttle_timeout(void *opaque) +{ + KBDState *s = opaque; + + if (s->status & KBD_STAT_OBF) { + return; + } + if (s->pending) { + kbd_update_irq(s); + } +} + static uint64_t kbd_read_status(void *opaque, hwaddr addr, unsigned size) { @@ -356,6 +378,10 @@ static uint64_t kbd_read_data(void *opaque, hwaddr addr, if (status & KBD_STAT_MOUSE_OBF) { s->obdata = ps2_read_data(s->mouse); } else { + if (s->throttle_timer) { + timer_mod(s->throttle_timer, + qemu_clock_get_us(QEMU_CLOCK_VIRTUAL) + 1000); + } s->obdata = ps2_read_data(s->kbd); } } @@ -417,6 +443,9 @@ static void kbd_reset(void *opaque) s->outport_present = false; s->pending = 0; kbd_deassert_irq(s); + if (s->throttle_timer) { + timer_del(s->throttle_timer); + } } static uint8_t kbd_outport_default(KBDState *s) @@ -451,6 +480,18 @@ static const VMStateDescription vmstate_kbd_outport = { } }; +static int kbd_pre_save(void *opaque) +{ + KBDState *s = opaque; + + s->migration_flags = 0; + if (s->throttle_timer && timer_pending(s->throttle_timer)) { + s->migration_flags |= KBD_MIGR_TIMER_PENDING; + } + + return 0; +} + static int kbd_post_load(void *opaque, int version_id) { KBDState *s = opaque; @@ -458,6 +499,9 @@ static int kbd_post_load(void *opaque, int version_id) s->outport = kbd_outport_default(s); } s->outport_present = false; + if (s->migration_flags & KBD_MIGR_TIMER_PENDING) { + kbd_throttle_timeout(s); + } return 0; } @@ -465,12 +509,14 @@ static const VMStateDescription vmstate_kbd = { .name = "pckbd", .version_id = 4, .minimum_version_id = 3, + .pre_save = kbd_pre_save, .post_load = kbd_post_load, .fields = (VMStateField[]) { VMSTATE_UINT8(write_cmd, KBDState), VMSTATE_UINT8(status, KBDState), VMSTATE_UINT8(mode, KBDState), VMSTATE_UINT8(pending, KBDState), + VMSTATE_UINT32_V(migration_flags, KBDState, 4), VMSTATE_UINT8_V(obdata, KBDState, 4), VMSTATE_END_OF_LIST() }, @@ -534,6 +580,7 @@ struct ISAKBDState { ISADevice parent_obj; KBDState kbd; + bool kbd_throttle; MemoryRegion io[2]; }; @@ -614,6 +661,10 @@ static void i8042_realizefn(DeviceState *dev, Error **errp) s->kbd = ps2_kbd_init(kbd_update_kbd_irq, s); s->mouse = ps2_mouse_init(kbd_update_aux_irq, s); + if (isa_s->kbd_throttle) { + s->throttle_timer = timer_new_us(QEMU_CLOCK_VIRTUAL, + kbd_throttle_timeout, s); + } qemu_register_reset(kbd_reset, s); } @@ -645,11 +696,17 @@ static void i8042_build_aml(ISADevice *isadev, Aml *scope) aml_append(scope, mou); } +static Property i8042_properties[] = { + DEFINE_PROP_BOOL("kbd-throttle", ISAKBDState, kbd_throttle, false), + DEFINE_PROP_END_OF_LIST(), +}; + static void i8042_class_initfn(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ISADeviceClass *isa = ISA_DEVICE_CLASS(klass); + device_class_set_props(dc, i8042_properties); dc->realize = i8042_realizefn; dc->vmsd = &vmstate_kbd_isa; isa->build_aml = i8042_build_aml; -- 2.26.2