cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

vmmouse.c (13520B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Driver for Virtual PS/2 Mouse on VMware and QEMU hypervisors.
      4 *
      5 * Copyright (C) 2014, VMware, Inc. All Rights Reserved.
      6 *
      7 * Twin device code is hugely inspired by the ALPS driver.
      8 * Authors:
      9 *   Dmitry Torokhov <dmitry.torokhov@gmail.com>
     10 *   Thomas Hellstrom <thellstrom@vmware.com>
     11 */
     12
     13#include <linux/input.h>
     14#include <linux/serio.h>
     15#include <linux/libps2.h>
     16#include <linux/slab.h>
     17#include <linux/module.h>
     18#include <asm/hypervisor.h>
     19#include <asm/vmware.h>
     20
     21#include "psmouse.h"
     22#include "vmmouse.h"
     23
     24#define VMMOUSE_PROTO_MAGIC			0x564D5868U
     25
     26/*
     27 * Main commands supported by the vmmouse hypervisor port.
     28 */
     29#define VMMOUSE_PROTO_CMD_GETVERSION		10
     30#define VMMOUSE_PROTO_CMD_ABSPOINTER_DATA	39
     31#define VMMOUSE_PROTO_CMD_ABSPOINTER_STATUS	40
     32#define VMMOUSE_PROTO_CMD_ABSPOINTER_COMMAND	41
     33#define VMMOUSE_PROTO_CMD_ABSPOINTER_RESTRICT   86
     34
     35/*
     36 * Subcommands for VMMOUSE_PROTO_CMD_ABSPOINTER_COMMAND
     37 */
     38#define VMMOUSE_CMD_ENABLE			0x45414552U
     39#define VMMOUSE_CMD_DISABLE			0x000000f5U
     40#define VMMOUSE_CMD_REQUEST_RELATIVE		0x4c455252U
     41#define VMMOUSE_CMD_REQUEST_ABSOLUTE		0x53424152U
     42
     43#define VMMOUSE_ERROR				0xffff0000U
     44
     45#define VMMOUSE_VERSION_ID			0x3442554aU
     46
     47#define VMMOUSE_RELATIVE_PACKET			0x00010000U
     48
     49#define VMMOUSE_LEFT_BUTTON			0x20
     50#define VMMOUSE_RIGHT_BUTTON			0x10
     51#define VMMOUSE_MIDDLE_BUTTON			0x08
     52
     53/*
     54 * VMMouse Restrict command
     55 */
     56#define VMMOUSE_RESTRICT_ANY                    0x00
     57#define VMMOUSE_RESTRICT_CPL0                   0x01
     58#define VMMOUSE_RESTRICT_IOPL                   0x02
     59
     60#define VMMOUSE_MAX_X                           0xFFFF
     61#define VMMOUSE_MAX_Y                           0xFFFF
     62
     63#define VMMOUSE_VENDOR "VMware"
     64#define VMMOUSE_NAME   "VMMouse"
     65
     66/**
     67 * struct vmmouse_data - private data structure for the vmmouse driver
     68 *
     69 * @abs_dev: "Absolute" device used to report absolute mouse movement.
     70 * @phys: Physical path for the absolute device.
     71 * @dev_name: Name attribute name for the absolute device.
     72 */
     73struct vmmouse_data {
     74	struct input_dev *abs_dev;
     75	char phys[32];
     76	char dev_name[128];
     77};
     78
     79/*
     80 * Hypervisor-specific bi-directional communication channel
     81 * implementing the vmmouse protocol. Should never execute on
     82 * bare metal hardware.
     83 */
     84#define VMMOUSE_CMD(cmd, in1, out1, out2, out3, out4)	\
     85({							\
     86	unsigned long __dummy1, __dummy2;		\
     87	__asm__ __volatile__ (VMWARE_HYPERCALL :	\
     88		"=a"(out1),				\
     89		"=b"(out2),				\
     90		"=c"(out3),				\
     91		"=d"(out4),				\
     92		"=S"(__dummy1),				\
     93		"=D"(__dummy2) :			\
     94		"a"(VMMOUSE_PROTO_MAGIC),		\
     95		"b"(in1),				\
     96		"c"(VMMOUSE_PROTO_CMD_##cmd),		\
     97		"d"(0) :			        \
     98		"memory");		                \
     99})
    100
    101/**
    102 * vmmouse_report_button - report button state on the correct input device
    103 *
    104 * @psmouse:  Pointer to the psmouse struct
    105 * @abs_dev:  The absolute input device
    106 * @rel_dev:  The relative input device
    107 * @pref_dev: The preferred device for reporting
    108 * @code:     Button code
    109 * @value:    Button value
    110 *
    111 * Report @value and @code on @pref_dev, unless the button is already
    112 * pressed on the other device, in which case the state is reported on that
    113 * device.
    114 */
    115static void vmmouse_report_button(struct psmouse *psmouse,
    116				  struct input_dev *abs_dev,
    117				  struct input_dev *rel_dev,
    118				  struct input_dev *pref_dev,
    119				  unsigned int code, int value)
    120{
    121	if (test_bit(code, abs_dev->key))
    122		pref_dev = abs_dev;
    123	else if (test_bit(code, rel_dev->key))
    124		pref_dev = rel_dev;
    125
    126	input_report_key(pref_dev, code, value);
    127}
    128
    129/**
    130 * vmmouse_report_events - process events on the vmmouse communications channel
    131 *
    132 * @psmouse: Pointer to the psmouse struct
    133 *
    134 * This function pulls events from the vmmouse communications channel and
    135 * reports them on the correct (absolute or relative) input device. When the
    136 * communications channel is drained, or if we've processed more than 255
    137 * psmouse commands, the function returns PSMOUSE_FULL_PACKET. If there is a
    138 * host- or synchronization error, the function returns PSMOUSE_BAD_DATA in
    139 * the hope that the caller will reset the communications channel.
    140 */
    141static psmouse_ret_t vmmouse_report_events(struct psmouse *psmouse)
    142{
    143	struct input_dev *rel_dev = psmouse->dev;
    144	struct vmmouse_data *priv = psmouse->private;
    145	struct input_dev *abs_dev = priv->abs_dev;
    146	struct input_dev *pref_dev;
    147	u32 status, x, y, z;
    148	u32 dummy1, dummy2, dummy3;
    149	unsigned int queue_length;
    150	unsigned int count = 255;
    151
    152	while (count--) {
    153		/* See if we have motion data. */
    154		VMMOUSE_CMD(ABSPOINTER_STATUS, 0,
    155			    status, dummy1, dummy2, dummy3);
    156		if ((status & VMMOUSE_ERROR) == VMMOUSE_ERROR) {
    157			psmouse_err(psmouse, "failed to fetch status data\n");
    158			/*
    159			 * After a few attempts this will result in
    160			 * reconnect.
    161			 */
    162			return PSMOUSE_BAD_DATA;
    163		}
    164
    165		queue_length = status & 0xffff;
    166		if (queue_length == 0)
    167			break;
    168
    169		if (queue_length % 4) {
    170			psmouse_err(psmouse, "invalid queue length\n");
    171			return PSMOUSE_BAD_DATA;
    172		}
    173
    174		/* Now get it */
    175		VMMOUSE_CMD(ABSPOINTER_DATA, 4, status, x, y, z);
    176
    177		/*
    178		 * And report what we've got. Prefer to report button
    179		 * events on the same device where we report motion events.
    180		 * This doesn't work well with the mouse wheel, though. See
    181		 * below. Ideally we would want to report that on the
    182		 * preferred device as well.
    183		 */
    184		if (status & VMMOUSE_RELATIVE_PACKET) {
    185			pref_dev = rel_dev;
    186			input_report_rel(rel_dev, REL_X, (s32)x);
    187			input_report_rel(rel_dev, REL_Y, -(s32)y);
    188		} else {
    189			pref_dev = abs_dev;
    190			input_report_abs(abs_dev, ABS_X, x);
    191			input_report_abs(abs_dev, ABS_Y, y);
    192		}
    193
    194		/* Xorg seems to ignore wheel events on absolute devices */
    195		input_report_rel(rel_dev, REL_WHEEL, -(s8)((u8) z));
    196
    197		vmmouse_report_button(psmouse, abs_dev, rel_dev,
    198				      pref_dev, BTN_LEFT,
    199				      status & VMMOUSE_LEFT_BUTTON);
    200		vmmouse_report_button(psmouse, abs_dev, rel_dev,
    201				      pref_dev, BTN_RIGHT,
    202				      status & VMMOUSE_RIGHT_BUTTON);
    203		vmmouse_report_button(psmouse, abs_dev, rel_dev,
    204				      pref_dev, BTN_MIDDLE,
    205				      status & VMMOUSE_MIDDLE_BUTTON);
    206		input_sync(abs_dev);
    207		input_sync(rel_dev);
    208	}
    209
    210	return PSMOUSE_FULL_PACKET;
    211}
    212
    213/**
    214 * vmmouse_process_byte - process data on the ps/2 channel
    215 *
    216 * @psmouse: Pointer to the psmouse struct
    217 *
    218 * When the ps/2 channel indicates that there is vmmouse data available,
    219 * call vmmouse channel processing. Otherwise, continue to accept bytes. If
    220 * there is a synchronization or communication data error, return
    221 * PSMOUSE_BAD_DATA in the hope that the caller will reset the mouse.
    222 */
    223static psmouse_ret_t vmmouse_process_byte(struct psmouse *psmouse)
    224{
    225	unsigned char *packet = psmouse->packet;
    226
    227	switch (psmouse->pktcnt) {
    228	case 1:
    229		return (packet[0] & 0x8) == 0x8 ?
    230			PSMOUSE_GOOD_DATA : PSMOUSE_BAD_DATA;
    231
    232	case 2:
    233		return PSMOUSE_GOOD_DATA;
    234
    235	default:
    236		return vmmouse_report_events(psmouse);
    237	}
    238}
    239
    240/**
    241 * vmmouse_disable - Disable vmmouse
    242 *
    243 * @psmouse: Pointer to the psmouse struct
    244 *
    245 * Tries to disable vmmouse mode.
    246 */
    247static void vmmouse_disable(struct psmouse *psmouse)
    248{
    249	u32 status;
    250	u32 dummy1, dummy2, dummy3, dummy4;
    251
    252	VMMOUSE_CMD(ABSPOINTER_COMMAND, VMMOUSE_CMD_DISABLE,
    253		    dummy1, dummy2, dummy3, dummy4);
    254
    255	VMMOUSE_CMD(ABSPOINTER_STATUS, 0,
    256		    status, dummy1, dummy2, dummy3);
    257
    258	if ((status & VMMOUSE_ERROR) != VMMOUSE_ERROR)
    259		psmouse_warn(psmouse, "failed to disable vmmouse device\n");
    260}
    261
    262/**
    263 * vmmouse_enable - Enable vmmouse and request absolute mode.
    264 *
    265 * @psmouse: Pointer to the psmouse struct
    266 *
    267 * Tries to enable vmmouse mode. Performs basic checks and requests
    268 * absolute vmmouse mode.
    269 * Returns 0 on success, -ENODEV on failure.
    270 */
    271static int vmmouse_enable(struct psmouse *psmouse)
    272{
    273	u32 status, version;
    274	u32 dummy1, dummy2, dummy3, dummy4;
    275
    276	/*
    277	 * Try enabling the device. If successful, we should be able to
    278	 * read valid version ID back from it.
    279	 */
    280	VMMOUSE_CMD(ABSPOINTER_COMMAND, VMMOUSE_CMD_ENABLE,
    281		    dummy1, dummy2, dummy3, dummy4);
    282
    283	/*
    284	 * See if version ID can be retrieved.
    285	 */
    286	VMMOUSE_CMD(ABSPOINTER_STATUS, 0, status, dummy1, dummy2, dummy3);
    287	if ((status & 0x0000ffff) == 0) {
    288		psmouse_dbg(psmouse, "empty flags - assuming no device\n");
    289		return -ENXIO;
    290	}
    291
    292	VMMOUSE_CMD(ABSPOINTER_DATA, 1 /* single item */,
    293		    version, dummy1, dummy2, dummy3);
    294	if (version != VMMOUSE_VERSION_ID) {
    295		psmouse_dbg(psmouse, "Unexpected version value: %u vs %u\n",
    296			    (unsigned) version, VMMOUSE_VERSION_ID);
    297		vmmouse_disable(psmouse);
    298		return -ENXIO;
    299	}
    300
    301	/*
    302	 * Restrict ioport access, if possible.
    303	 */
    304	VMMOUSE_CMD(ABSPOINTER_RESTRICT, VMMOUSE_RESTRICT_CPL0,
    305		    dummy1, dummy2, dummy3, dummy4);
    306
    307	VMMOUSE_CMD(ABSPOINTER_COMMAND, VMMOUSE_CMD_REQUEST_ABSOLUTE,
    308		    dummy1, dummy2, dummy3, dummy4);
    309
    310	return 0;
    311}
    312
    313/*
    314 * Array of supported hypervisors.
    315 */
    316static enum x86_hypervisor_type vmmouse_supported_hypervisors[] = {
    317	X86_HYPER_VMWARE,
    318	X86_HYPER_KVM,
    319};
    320
    321/**
    322 * vmmouse_check_hypervisor - Check if we're running on a supported hypervisor
    323 */
    324static bool vmmouse_check_hypervisor(void)
    325{
    326	int i;
    327
    328	for (i = 0; i < ARRAY_SIZE(vmmouse_supported_hypervisors); i++)
    329		if (vmmouse_supported_hypervisors[i] == x86_hyper_type)
    330			return true;
    331
    332	return false;
    333}
    334
    335/**
    336 * vmmouse_detect - Probe whether vmmouse is available
    337 *
    338 * @psmouse: Pointer to the psmouse struct
    339 * @set_properties: Whether to set psmouse name and vendor
    340 *
    341 * Returns 0 if vmmouse channel is available. Negative error code if not.
    342 */
    343int vmmouse_detect(struct psmouse *psmouse, bool set_properties)
    344{
    345	u32 response, version, dummy1, dummy2;
    346
    347	if (!vmmouse_check_hypervisor()) {
    348		psmouse_dbg(psmouse,
    349			    "VMMouse not running on supported hypervisor.\n");
    350		return -ENXIO;
    351	}
    352
    353	/* Check if the device is present */
    354	response = ~VMMOUSE_PROTO_MAGIC;
    355	VMMOUSE_CMD(GETVERSION, 0, version, response, dummy1, dummy2);
    356	if (response != VMMOUSE_PROTO_MAGIC || version == 0xffffffffU)
    357		return -ENXIO;
    358
    359	if (set_properties) {
    360		psmouse->vendor = VMMOUSE_VENDOR;
    361		psmouse->name = VMMOUSE_NAME;
    362		psmouse->model = version;
    363	}
    364
    365	return 0;
    366}
    367
    368/**
    369 * vmmouse_reset - Disable vmmouse and reset
    370 *
    371 * @psmouse: Pointer to the psmouse struct
    372 *
    373 * Tries to disable vmmouse mode before enter suspend.
    374 */
    375static void vmmouse_reset(struct psmouse *psmouse)
    376{
    377	vmmouse_disable(psmouse);
    378	psmouse_reset(psmouse);
    379}
    380
    381/**
    382 * vmmouse_disconnect - Take down vmmouse driver
    383 *
    384 * @psmouse: Pointer to the psmouse struct
    385 *
    386 * Takes down vmmouse driver and frees resources set up in vmmouse_init().
    387 */
    388static void vmmouse_disconnect(struct psmouse *psmouse)
    389{
    390	struct vmmouse_data *priv = psmouse->private;
    391
    392	vmmouse_disable(psmouse);
    393	psmouse_reset(psmouse);
    394	input_unregister_device(priv->abs_dev);
    395	kfree(priv);
    396}
    397
    398/**
    399 * vmmouse_reconnect - Reset the ps/2 - and vmmouse connections
    400 *
    401 * @psmouse: Pointer to the psmouse struct
    402 *
    403 * Attempts to reset the mouse connections. Returns 0 on success and
    404 * -1 on failure.
    405 */
    406static int vmmouse_reconnect(struct psmouse *psmouse)
    407{
    408	int error;
    409
    410	psmouse_reset(psmouse);
    411	vmmouse_disable(psmouse);
    412	error = vmmouse_enable(psmouse);
    413	if (error) {
    414		psmouse_err(psmouse,
    415			    "Unable to re-enable mouse when reconnecting, err: %d\n",
    416			    error);
    417		return error;
    418	}
    419
    420	return 0;
    421}
    422
    423/**
    424 * vmmouse_init - Initialize the vmmouse driver
    425 *
    426 * @psmouse: Pointer to the psmouse struct
    427 *
    428 * Requests the device and tries to enable vmmouse mode.
    429 * If successful, sets up the input device for relative movement events.
    430 * It also allocates another input device and sets it up for absolute motion
    431 * events. Returns 0 on success and -1 on failure.
    432 */
    433int vmmouse_init(struct psmouse *psmouse)
    434{
    435	struct vmmouse_data *priv;
    436	struct input_dev *rel_dev = psmouse->dev, *abs_dev;
    437	int error;
    438
    439	psmouse_reset(psmouse);
    440	error = vmmouse_enable(psmouse);
    441	if (error)
    442		return error;
    443
    444	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
    445	abs_dev = input_allocate_device();
    446	if (!priv || !abs_dev) {
    447		error = -ENOMEM;
    448		goto init_fail;
    449	}
    450
    451	priv->abs_dev = abs_dev;
    452	psmouse->private = priv;
    453
    454	/* Set up and register absolute device */
    455	snprintf(priv->phys, sizeof(priv->phys), "%s/input1",
    456		 psmouse->ps2dev.serio->phys);
    457
    458	/* Mimic name setup for relative device in psmouse-base.c */
    459	snprintf(priv->dev_name, sizeof(priv->dev_name), "%s %s %s",
    460		 VMMOUSE_PSNAME, VMMOUSE_VENDOR, VMMOUSE_NAME);
    461	abs_dev->phys = priv->phys;
    462	abs_dev->name = priv->dev_name;
    463	abs_dev->id.bustype = BUS_I8042;
    464	abs_dev->id.vendor = 0x0002;
    465	abs_dev->id.product = PSMOUSE_VMMOUSE;
    466	abs_dev->id.version = psmouse->model;
    467	abs_dev->dev.parent = &psmouse->ps2dev.serio->dev;
    468
    469	/* Set absolute device capabilities */
    470	input_set_capability(abs_dev, EV_KEY, BTN_LEFT);
    471	input_set_capability(abs_dev, EV_KEY, BTN_RIGHT);
    472	input_set_capability(abs_dev, EV_KEY, BTN_MIDDLE);
    473	input_set_capability(abs_dev, EV_ABS, ABS_X);
    474	input_set_capability(abs_dev, EV_ABS, ABS_Y);
    475	input_set_abs_params(abs_dev, ABS_X, 0, VMMOUSE_MAX_X, 0, 0);
    476	input_set_abs_params(abs_dev, ABS_Y, 0, VMMOUSE_MAX_Y, 0, 0);
    477
    478	error = input_register_device(priv->abs_dev);
    479	if (error)
    480		goto init_fail;
    481
    482	/* Add wheel capability to the relative device */
    483	input_set_capability(rel_dev, EV_REL, REL_WHEEL);
    484
    485	psmouse->protocol_handler = vmmouse_process_byte;
    486	psmouse->disconnect = vmmouse_disconnect;
    487	psmouse->reconnect = vmmouse_reconnect;
    488	psmouse->cleanup = vmmouse_reset;
    489
    490	return 0;
    491
    492init_fail:
    493	vmmouse_disable(psmouse);
    494	psmouse_reset(psmouse);
    495	input_free_device(abs_dev);
    496	kfree(priv);
    497	psmouse->private = NULL;
    498
    499	return error;
    500}