From patchwork Mon May 7 12:00:22 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Cameron Esfahani via X-Patchwork-Id: 909712 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=nongnu.org Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=hostfission.com header.i=@hostfission.com header.b="JhHcvyY4"; dkim-atps=neutral Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 40fh6D1NDWz9s34 for ; Mon, 7 May 2018 22:01:08 +1000 (AEST) Received: from localhost ([::1]:45826 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fFepF-00063X-EA for incoming@patchwork.ozlabs.org; Mon, 07 May 2018 08:01:05 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:43610) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fFeoj-0005zu-3s for qemu-devel@nongnu.org; Mon, 07 May 2018 08:00:38 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fFeod-0005x7-UG for qemu-devel@nongnu.org; Mon, 07 May 2018 08:00:33 -0400 Received: from mail1.hostfission.com ([139.99.139.48]:49496) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fFeod-0005tL-Jn for qemu-devel@nongnu.org; Mon, 07 May 2018 08:00:27 -0400 Received: from www1.hostfission.com (www1.hostfission.com [139.99.139.52]) by mail1.hostfission.com (Postfix) with ESMTP id E43FD43ED6 for ; Mon, 7 May 2018 22:00:22 +1000 (AEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=hostfission.com; s=mail; t=1525694422; bh=6F16zVqC84IWS2MVZT3LaKV5v/FX4LGVLg3cEcOA5sA=; h=To:Subject:Date:From:From; b=JhHcvyY4DFCBm4yFSKsecD9Q5bKQmadKJ5z+hZ9MBG57TJoRuvwPm09nNvhQzbq+T o06OBEqpkwqpY9W62VF8ZOmJTQiqQmeUJftv48j5873dDM9aXGiycWJ/pjEuJxWmE6 67cN5o0HIsM5BEsfWYch34MpQxLreKWK8Kg2MBig= Received: by www1.hostfission.com (Postfix, from userid 1000) id DFFC480EE8; Mon, 7 May 2018 22:00:22 +1000 (AEST) To: qemu-devel@nongnu.org X-PHP-Originating-Script: 0:rcube.php MIME-Version: 1.0 Date: Mon, 07 May 2018 22:00:22 +1000 Message-ID: X-Sender: geoff@hostfission.com User-Agent: Roundcube Webmail/1.2.3 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 139.99.139.48 Subject: [Qemu-devel] [PATCH 1/2] ps2: Clear the queue on PS/2 mouse reset and obey device disable X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: geoff--- via Qemu-devel From: Cameron Esfahani via Reply-To: geoff@hostfission.com Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" This allows guest's to correctly reinitialize and identify the mouse should the guest decide to re-scan or reset during mouse input events. Signed-off-by: Geoffrey McRae --- hw/input/ps2.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hw/input/ps2.c b/hw/input/ps2.c index 06f5d2ac4a..6edf046820 100644 --- a/hw/input/ps2.c +++ b/hw/input/ps2.c @@ -673,6 +673,9 @@ static void ps2_mouse_sync(DeviceState *dev) { PS2MouseState *s = (PS2MouseState *)dev; + if (!(s->mouse_status & MOUSE_STATUS_ENABLED)) + return; + if (s->mouse_buttons) { qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER); } @@ -776,6 +779,7 @@ void ps2_write_mouse(void *opaque, int val) s->mouse_resolution = 2; s->mouse_status = 0; s->mouse_type = 0; + ps2_reset_queue(&s->common); ps2_queue(&s->common, AUX_ACK); ps2_queue(&s->common, 0xaa); ps2_queue(&s->common, s->mouse_type); From patchwork Mon May 7 12:03:10 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Cameron Esfahani via X-Patchwork-Id: 909714 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=nongnu.org Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=hostfission.com header.i=@hostfission.com header.b="cacK8BBk"; dkim-atps=neutral Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 40fh9Q3wdqz9s34 for ; Mon, 7 May 2018 22:03:54 +1000 (AEST) Received: from localhost ([::1]:45858 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fFerv-0007PO-QF for incoming@patchwork.ozlabs.org; Mon, 07 May 2018 08:03:51 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:44921) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fFerN-0007Nv-HB for qemu-devel@nongnu.org; Mon, 07 May 2018 08:03:19 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fFerI-0000UB-Ir for qemu-devel@nongnu.org; Mon, 07 May 2018 08:03:17 -0400 Received: from mail1.hostfission.com ([139.99.139.48]:49522) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fFerI-0000Te-0X for qemu-devel@nongnu.org; Mon, 07 May 2018 08:03:12 -0400 Received: from www1.hostfission.com (www1.hostfission.com [139.99.139.52]) by mail1.hostfission.com (Postfix) with ESMTP id A669C43ED6 for ; Mon, 7 May 2018 22:03:10 +1000 (AEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=hostfission.com; s=mail; t=1525694590; bh=NN+n5x03fNcwmOq8f9J+doxmqwgIWmAgLUfjz7aHzXo=; h=To:Subject:Date:From:From; b=cacK8BBkvnMBMi85ALfHovfxQ5EmUqjuUMzVRSUQcYyR1pgSD9hVW2Prz85pAF9iT e3ox9/nNC5hFRtL7OwrBgvN8azZpWU4Jq4njlf4D0cu4Q1lrxac3Hc4ugOD4LoYv3J N+HBNYWHPf7/CM1KImdOmkfIk0rAgXZOzF2dsKvM= Received: by www1.hostfission.com (Postfix, from userid 1000) id 9D40181115; Mon, 7 May 2018 22:03:10 +1000 (AEST) To: qemu-devel@nongnu.org X-PHP-Originating-Script: 0:rcube.php MIME-Version: 1.0 Date: Mon, 07 May 2018 22:03:10 +1000 Message-ID: X-Sender: geoff@hostfission.com User-Agent: Roundcube Webmail/1.2.3 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 139.99.139.48 Subject: [Qemu-devel] [PATCH 2/2] ps2: Fix mouse stream corruption due to lost data X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: geoff--- via Qemu-devel From: Cameron Esfahani via Reply-To: geoff@hostfission.com Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" This fixes an issue by adding bounds checking to multi-byte packets where the PS/2 mouse data stream may become corrupted due to data being discarded when the PS/2 ringbuffer is full. Interrupts for Multi-byte responses are postponed until the final byte has been queued. These changes fix a bug where windows guests drop the mouse device entirely requring the guest to be restarted. Signed-off-by: Geoffrey McRae --- hw/input/pckbd.c | 6 +-- hw/input/ps2.c | 160 +++++++++++++++++++++++++++++++++++++------------------ 2 files changed, 110 insertions(+), 56 deletions(-) } @@ -490,72 +528,80 @@ void ps2_write_keyboard(void *opaque, int val) case -1: switch(val) { case 0x00: - ps2_queue(&s->common, KBD_REPLY_ACK); + ps2_queue_raise(&s->common, KBD_REPLY_ACK); break; case 0x05: - ps2_queue(&s->common, KBD_REPLY_RESEND); + ps2_queue_raise(&s->common, KBD_REPLY_RESEND); break; case KBD_CMD_GET_ID: - ps2_queue(&s->common, KBD_REPLY_ACK); /* We emulate a MF2 AT keyboard here */ - ps2_queue(&s->common, KBD_REPLY_ID); if (s->translate) - ps2_queue(&s->common, 0x41); + ps2_queue_bytes(&s->common, 3, + KBD_REPLY_ACK, + KBD_REPLY_ID, + 0x41); else - ps2_queue(&s->common, 0x83); + ps2_queue_bytes(&s->common, 3, + KBD_REPLY_ACK, + KBD_REPLY_ID, + 0x83); break; case KBD_CMD_ECHO: - ps2_queue(&s->common, KBD_CMD_ECHO); + ps2_queue_raise(&s->common, KBD_CMD_ECHO); break; case KBD_CMD_ENABLE: s->scan_enabled = 1; - ps2_queue(&s->common, KBD_REPLY_ACK); + ps2_queue_raise(&s->common, KBD_REPLY_ACK); break; case KBD_CMD_SCANCODE: case KBD_CMD_SET_LEDS: case KBD_CMD_SET_RATE: s->common.write_cmd = val; - ps2_queue(&s->common, KBD_REPLY_ACK); + ps2_queue_raise(&s->common, KBD_REPLY_ACK); break; case KBD_CMD_RESET_DISABLE: ps2_reset_keyboard(s); s->scan_enabled = 0; - ps2_queue(&s->common, KBD_REPLY_ACK); + ps2_queue_raise(&s->common, KBD_REPLY_ACK); break; case KBD_CMD_RESET_ENABLE: ps2_reset_keyboard(s); s->scan_enabled = 1; - ps2_queue(&s->common, KBD_REPLY_ACK); + ps2_queue_raise(&s->common, KBD_REPLY_ACK); break; case KBD_CMD_RESET: ps2_reset_keyboard(s); - ps2_queue(&s->common, KBD_REPLY_ACK); - ps2_queue(&s->common, KBD_REPLY_POR); + ps2_queue_bytes(&s->common, 2, + KBD_REPLY_ACK, + KBD_REPLY_POR); break; default: - ps2_queue(&s->common, KBD_REPLY_RESEND); + ps2_queue_raise(&s->common, KBD_REPLY_RESEND); break; } break; case KBD_CMD_SCANCODE: if (val == 0) { - ps2_queue(&s->common, KBD_REPLY_ACK); - ps2_put_keycode(s, s->scancode_set); + if (s->common.queue.count <= PS2_QUEUE_SIZE - 2) + { + ps2_queue_raise(&s->common, KBD_REPLY_ACK); + ps2_put_keycode(s, s->scancode_set); + } } else if (val >= 1 && val <= 3) { s->scancode_set = val; - ps2_queue(&s->common, KBD_REPLY_ACK); + ps2_queue_raise(&s->common, KBD_REPLY_ACK); } else { - ps2_queue(&s->common, KBD_REPLY_RESEND); + ps2_queue_raise(&s->common, KBD_REPLY_RESEND); } s->common.write_cmd = -1; break; case KBD_CMD_SET_LEDS: ps2_set_ledstate(s, val); - ps2_queue(&s->common, KBD_REPLY_ACK); + ps2_queue_raise(&s->common, KBD_REPLY_ACK); s->common.write_cmd = -1; break; case KBD_CMD_SET_RATE: - ps2_queue(&s->common, KBD_REPLY_ACK); + ps2_queue_raise(&s->common, KBD_REPLY_ACK); s->common.write_cmd = -1; break; } @@ -572,11 +618,15 @@ void ps2_keyboard_set_translation(void *opaque, int mode) s->translate = mode; } -static void ps2_mouse_send_packet(PS2MouseState *s) +static int ps2_mouse_send_packet(PS2MouseState *s) { unsigned int b; int dx1, dy1, dz1; + const int needed = 3 + (s->mouse_type - 2); + if (PS2_QUEUE_SIZE - s->common.queue.count < needed) + return 0; + dx1 = s->mouse_dx; dy1 = s->mouse_dy; dz1 = s->mouse_dz; @@ -614,11 +664,15 @@ static void ps2_mouse_send_packet(PS2MouseState *s) break; } + ps2_raise(&s->common); + trace_ps2_mouse_send_packet(s, dx1, dy1, dz1, b); /* update deltas */ s->mouse_dx -= dx1; s->mouse_dy -= dy1; s->mouse_dz -= dz1; + + return 1; } static void ps2_mouse_event(DeviceState *dev, QemuConsole *src, @@ -680,10 +734,7 @@ static void ps2_mouse_sync(DeviceState *dev) qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER); } if (!(s->mouse_status & MOUSE_STATUS_REMOTE)) { - while (s->common.queue.count < PS2_QUEUE_SIZE - 4) { - /* if not remote, send event. Multiple events are sent if - too big deltas */ - ps2_mouse_send_packet(s); + while(ps2_mouse_send_packet(s)) { if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0) break; } @@ -713,66 +764,68 @@ void ps2_write_mouse(void *opaque, int val) if (s->mouse_wrap) { if (val == AUX_RESET_WRAP) { s->mouse_wrap = 0; - ps2_queue(&s->common, AUX_ACK); + ps2_queue_raise(&s->common, AUX_ACK); return; } else if (val != AUX_RESET) { - ps2_queue(&s->common, val); + ps2_queue_raise(&s->common, val); return; } } switch(val) { case AUX_SET_SCALE11: s->mouse_status &= ~MOUSE_STATUS_SCALE21; - ps2_queue(&s->common, AUX_ACK); + ps2_queue_raise(&s->common, AUX_ACK); break; case AUX_SET_SCALE21: s->mouse_status |= MOUSE_STATUS_SCALE21; - ps2_queue(&s->common, AUX_ACK); + ps2_queue_raise(&s->common, AUX_ACK); break; case AUX_SET_STREAM: s->mouse_status &= ~MOUSE_STATUS_REMOTE; - ps2_queue(&s->common, AUX_ACK); + ps2_queue_raise(&s->common, AUX_ACK); break; case AUX_SET_WRAP: s->mouse_wrap = 1; - ps2_queue(&s->common, AUX_ACK); + ps2_queue_raise(&s->common, AUX_ACK); break; case AUX_SET_REMOTE: s->mouse_status |= MOUSE_STATUS_REMOTE; - ps2_queue(&s->common, AUX_ACK); + ps2_queue_raise(&s->common, AUX_ACK); break; case AUX_GET_TYPE: - ps2_queue(&s->common, AUX_ACK); - ps2_queue(&s->common, s->mouse_type); + ps2_queue_bytes(&s->common, 2, + AUX_ACK, + s->mouse_type); break; case AUX_SET_RES: case AUX_SET_SAMPLE: s->common.write_cmd = val; - ps2_queue(&s->common, AUX_ACK); + ps2_queue_raise(&s->common, AUX_ACK); break; case AUX_GET_SCALE: - ps2_queue(&s->common, AUX_ACK); - ps2_queue(&s->common, s->mouse_status); - ps2_queue(&s->common, s->mouse_resolution); - ps2_queue(&s->common, s->mouse_sample_rate); + ps2_queue_bytes(&s->common, 4, + AUX_ACK, + s->mouse_status, + s->mouse_resolution, + s->mouse_sample_rate); break; case AUX_POLL: - ps2_queue(&s->common, AUX_ACK); + ps2_queue_raise(&s->common, AUX_ACK); ps2_mouse_send_packet(s); break; case AUX_ENABLE_DEV: s->mouse_status |= MOUSE_STATUS_ENABLED; - ps2_queue(&s->common, AUX_ACK); + ps2_queue_raise(&s->common, AUX_ACK); break; case AUX_DISABLE_DEV: s->mouse_status &= ~MOUSE_STATUS_ENABLED; - ps2_queue(&s->common, AUX_ACK); + ps2_queue_raise(&s->common, AUX_ACK); break; case AUX_SET_DEFAULT: s->mouse_sample_rate = 100; s->mouse_resolution = 2; s->mouse_status = 0; - ps2_queue(&s->common, AUX_ACK); + ps2_queue_raise(&s->common, AUX_ACK); break; case AUX_RESET: s->mouse_sample_rate = 100; @@ -780,9 +833,10 @@ void ps2_write_mouse(void *opaque, int val) s->mouse_status = 0; s->mouse_type = 0; ps2_reset_queue(&s->common); - ps2_queue(&s->common, AUX_ACK); - ps2_queue(&s->common, 0xaa); - ps2_queue(&s->common, s->mouse_type); + ps2_queue_bytes(&s->common, 3, + AUX_ACK, + 0xaa, + s->mouse_type); break; default: break; @@ -816,12 +870,12 @@ void ps2_write_mouse(void *opaque, int val) s->mouse_detect_state = 0; break; } - ps2_queue(&s->common, AUX_ACK); + ps2_queue_raise(&s->common, AUX_ACK); s->common.write_cmd = -1; break; case AUX_SET_RES: s->mouse_resolution = val; - ps2_queue(&s->common, AUX_ACK); + ps2_queue_raise(&s->common, AUX_ACK); s->common.write_cmd = -1; break; } diff --git a/hw/input/pckbd.c b/hw/input/pckbd.c index f17f18e51b..004ea3466d 100644 --- a/hw/input/pckbd.c +++ b/hw/input/pckbd.c @@ -216,9 +216,9 @@ static uint64_t kbd_read_status(void *opaque, hwaddr addr, static void kbd_queue(KBDState *s, int b, int aux) { if (aux) - ps2_queue(s->mouse, b); + ps2_queue_raise(s->mouse, b); else - ps2_queue(s->kbd, b); + ps2_queue_raise(s->kbd, b); } static void outport_write(KBDState *s, uint32_t val) diff --git a/hw/input/ps2.c b/hw/input/ps2.c index 6edf046820..011290920f 100644 --- a/hw/input/ps2.c +++ b/hw/input/ps2.c @@ -192,12 +192,50 @@ void ps2_queue(PS2State *s, int b) { PS2Queue *q = &s->queue; - if (q->count >= PS2_QUEUE_SIZE - 1) + if (q->count == PS2_QUEUE_SIZE) + { + printf("Warning! PS2 Queue Overflow!\n"); return; + } + q->data[q->wptr] = b; if (++q->wptr == PS2_QUEUE_SIZE) q->wptr = 0; q->count++; +} + +void ps2_raise(PS2State *s) +{ + s->update_irq(s->update_arg, 1); +} + +void ps2_queue_raise(PS2State *s, int b) +{ + ps2_queue(s, b); + s->update_irq(s->update_arg, 1); +} + +void ps2_queue_bytes(PS2State *s, const int length, ...) +{ + PS2Queue *q = &s->queue; + + if (PS2_QUEUE_SIZE - q->count < length) { + printf("Unable to send %d bytes, buffer full\n", length); + return; + } + + va_list args; + va_start(args, length); + + for(int i = 0; i < length; ++i) + { + q->data[q->wptr] = va_arg(args, int); + if (++q->wptr == PS2_QUEUE_SIZE) + q->wptr = 0; + q->count++; + } + + va_end(args); s->update_irq(s->update_arg, 1); } @@ -213,13 +251,13 @@ static void ps2_put_keycode(void *opaque, int keycode) if (keycode == 0xf0) { s->need_high_bit = true; } else if (s->need_high_bit) { - ps2_queue(&s->common, translate_table[keycode] | 0x80); + ps2_queue_raise(&s->common, translate_table[keycode] | 0x80); s->need_high_bit = false; } else { - ps2_queue(&s->common, translate_table[keycode]); + ps2_queue_raise(&s->common, translate_table[keycode]); } } else { - ps2_queue(&s->common, keycode); + ps2_queue_raise(&s->common, keycode); }