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

hid-hyperv.c (13625B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 *  Copyright (c) 2009, Citrix Systems, Inc.
      4 *  Copyright (c) 2010, Microsoft Corporation.
      5 *  Copyright (c) 2011, Novell Inc.
      6 */
      7#include <linux/init.h>
      8#include <linux/module.h>
      9#include <linux/device.h>
     10#include <linux/completion.h>
     11#include <linux/input.h>
     12#include <linux/hid.h>
     13#include <linux/hiddev.h>
     14#include <linux/hyperv.h>
     15
     16
     17struct hv_input_dev_info {
     18	unsigned int size;
     19	unsigned short vendor;
     20	unsigned short product;
     21	unsigned short version;
     22	unsigned short reserved[11];
     23};
     24
     25/* The maximum size of a synthetic input message. */
     26#define SYNTHHID_MAX_INPUT_REPORT_SIZE 16
     27
     28/*
     29 * Current version
     30 *
     31 * History:
     32 * Beta, RC < 2008/1/22        1,0
     33 * RC > 2008/1/22              2,0
     34 */
     35#define SYNTHHID_INPUT_VERSION_MAJOR	2
     36#define SYNTHHID_INPUT_VERSION_MINOR	0
     37#define SYNTHHID_INPUT_VERSION		(SYNTHHID_INPUT_VERSION_MINOR | \
     38					 (SYNTHHID_INPUT_VERSION_MAJOR << 16))
     39
     40
     41#pragma pack(push, 1)
     42/*
     43 * Message types in the synthetic input protocol
     44 */
     45enum synthhid_msg_type {
     46	SYNTH_HID_PROTOCOL_REQUEST,
     47	SYNTH_HID_PROTOCOL_RESPONSE,
     48	SYNTH_HID_INITIAL_DEVICE_INFO,
     49	SYNTH_HID_INITIAL_DEVICE_INFO_ACK,
     50	SYNTH_HID_INPUT_REPORT,
     51	SYNTH_HID_MAX
     52};
     53
     54/*
     55 * Basic message structures.
     56 */
     57struct synthhid_msg_hdr {
     58	enum synthhid_msg_type type;
     59	u32 size;
     60};
     61
     62struct synthhid_msg {
     63	struct synthhid_msg_hdr header;
     64	char data[1]; /* Enclosed message */
     65};
     66
     67union synthhid_version {
     68	struct {
     69		u16 minor_version;
     70		u16 major_version;
     71	};
     72	u32 version;
     73};
     74
     75/*
     76 * Protocol messages
     77 */
     78struct synthhid_protocol_request {
     79	struct synthhid_msg_hdr header;
     80	union synthhid_version version_requested;
     81};
     82
     83struct synthhid_protocol_response {
     84	struct synthhid_msg_hdr header;
     85	union synthhid_version version_requested;
     86	unsigned char approved;
     87};
     88
     89struct synthhid_device_info {
     90	struct synthhid_msg_hdr header;
     91	struct hv_input_dev_info hid_dev_info;
     92	struct hid_descriptor hid_descriptor;
     93};
     94
     95struct synthhid_device_info_ack {
     96	struct synthhid_msg_hdr header;
     97	unsigned char reserved;
     98};
     99
    100struct synthhid_input_report {
    101	struct synthhid_msg_hdr header;
    102	char buffer[1];
    103};
    104
    105#pragma pack(pop)
    106
    107#define INPUTVSC_SEND_RING_BUFFER_SIZE	VMBUS_RING_SIZE(36 * 1024)
    108#define INPUTVSC_RECV_RING_BUFFER_SIZE	VMBUS_RING_SIZE(36 * 1024)
    109
    110
    111enum pipe_prot_msg_type {
    112	PIPE_MESSAGE_INVALID,
    113	PIPE_MESSAGE_DATA,
    114	PIPE_MESSAGE_MAXIMUM
    115};
    116
    117
    118struct pipe_prt_msg {
    119	enum pipe_prot_msg_type type;
    120	u32 size;
    121	char data[1];
    122};
    123
    124struct  mousevsc_prt_msg {
    125	enum pipe_prot_msg_type type;
    126	u32 size;
    127	union {
    128		struct synthhid_protocol_request request;
    129		struct synthhid_protocol_response response;
    130		struct synthhid_device_info_ack ack;
    131	};
    132};
    133
    134/*
    135 * Represents an mousevsc device
    136 */
    137struct mousevsc_dev {
    138	struct hv_device	*device;
    139	bool			init_complete;
    140	bool			connected;
    141	struct mousevsc_prt_msg	protocol_req;
    142	struct mousevsc_prt_msg	protocol_resp;
    143	/* Synchronize the request/response if needed */
    144	struct completion	wait_event;
    145	int			dev_info_status;
    146
    147	struct hid_descriptor	*hid_desc;
    148	unsigned char		*report_desc;
    149	u32			report_desc_size;
    150	struct hv_input_dev_info hid_dev_info;
    151	struct hid_device       *hid_device;
    152	u8			input_buf[HID_MAX_BUFFER_SIZE];
    153};
    154
    155
    156static struct mousevsc_dev *mousevsc_alloc_device(struct hv_device *device)
    157{
    158	struct mousevsc_dev *input_dev;
    159
    160	input_dev = kzalloc(sizeof(struct mousevsc_dev), GFP_KERNEL);
    161
    162	if (!input_dev)
    163		return NULL;
    164
    165	input_dev->device = device;
    166	hv_set_drvdata(device, input_dev);
    167	init_completion(&input_dev->wait_event);
    168	input_dev->init_complete = false;
    169
    170	return input_dev;
    171}
    172
    173static void mousevsc_free_device(struct mousevsc_dev *device)
    174{
    175	kfree(device->hid_desc);
    176	kfree(device->report_desc);
    177	hv_set_drvdata(device->device, NULL);
    178	kfree(device);
    179}
    180
    181static void mousevsc_on_receive_device_info(struct mousevsc_dev *input_device,
    182				struct synthhid_device_info *device_info)
    183{
    184	int ret = 0;
    185	struct hid_descriptor *desc;
    186	struct mousevsc_prt_msg ack;
    187
    188	input_device->dev_info_status = -ENOMEM;
    189
    190	input_device->hid_dev_info = device_info->hid_dev_info;
    191	desc = &device_info->hid_descriptor;
    192	if (desc->bLength == 0)
    193		goto cleanup;
    194
    195	/* The pointer is not NULL when we resume from hibernation */
    196	kfree(input_device->hid_desc);
    197	input_device->hid_desc = kmemdup(desc, desc->bLength, GFP_ATOMIC);
    198
    199	if (!input_device->hid_desc)
    200		goto cleanup;
    201
    202	input_device->report_desc_size = le16_to_cpu(
    203					desc->desc[0].wDescriptorLength);
    204	if (input_device->report_desc_size == 0) {
    205		input_device->dev_info_status = -EINVAL;
    206		goto cleanup;
    207	}
    208
    209	/* The pointer is not NULL when we resume from hibernation */
    210	kfree(input_device->report_desc);
    211	input_device->report_desc = kzalloc(input_device->report_desc_size,
    212					  GFP_ATOMIC);
    213
    214	if (!input_device->report_desc) {
    215		input_device->dev_info_status = -ENOMEM;
    216		goto cleanup;
    217	}
    218
    219	memcpy(input_device->report_desc,
    220	       ((unsigned char *)desc) + desc->bLength,
    221	       le16_to_cpu(desc->desc[0].wDescriptorLength));
    222
    223	/* Send the ack */
    224	memset(&ack, 0, sizeof(struct mousevsc_prt_msg));
    225
    226	ack.type = PIPE_MESSAGE_DATA;
    227	ack.size = sizeof(struct synthhid_device_info_ack);
    228
    229	ack.ack.header.type = SYNTH_HID_INITIAL_DEVICE_INFO_ACK;
    230	ack.ack.header.size = 1;
    231	ack.ack.reserved = 0;
    232
    233	ret = vmbus_sendpacket(input_device->device->channel,
    234			&ack,
    235			sizeof(struct pipe_prt_msg) - sizeof(unsigned char) +
    236			sizeof(struct synthhid_device_info_ack),
    237			(unsigned long)&ack,
    238			VM_PKT_DATA_INBAND,
    239			VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
    240
    241	if (!ret)
    242		input_device->dev_info_status = 0;
    243
    244cleanup:
    245	complete(&input_device->wait_event);
    246
    247	return;
    248}
    249
    250static void mousevsc_on_receive(struct hv_device *device,
    251				struct vmpacket_descriptor *packet)
    252{
    253	struct pipe_prt_msg *pipe_msg;
    254	struct synthhid_msg *hid_msg;
    255	struct mousevsc_dev *input_dev = hv_get_drvdata(device);
    256	struct synthhid_input_report *input_report;
    257	size_t len;
    258
    259	pipe_msg = (struct pipe_prt_msg *)((unsigned long)packet +
    260						(packet->offset8 << 3));
    261
    262	if (pipe_msg->type != PIPE_MESSAGE_DATA)
    263		return;
    264
    265	hid_msg = (struct synthhid_msg *)pipe_msg->data;
    266
    267	switch (hid_msg->header.type) {
    268	case SYNTH_HID_PROTOCOL_RESPONSE:
    269		/*
    270		 * While it will be impossible for us to protect against
    271		 * malicious/buggy hypervisor/host, add a check here to
    272		 * ensure we don't corrupt memory.
    273		 */
    274		if ((pipe_msg->size + sizeof(struct pipe_prt_msg)
    275			- sizeof(unsigned char))
    276			> sizeof(struct mousevsc_prt_msg)) {
    277			WARN_ON(1);
    278			break;
    279		}
    280
    281		memcpy(&input_dev->protocol_resp, pipe_msg,
    282		       pipe_msg->size + sizeof(struct pipe_prt_msg) -
    283		       sizeof(unsigned char));
    284		complete(&input_dev->wait_event);
    285		break;
    286
    287	case SYNTH_HID_INITIAL_DEVICE_INFO:
    288		WARN_ON(pipe_msg->size < sizeof(struct hv_input_dev_info));
    289
    290		/*
    291		 * Parse out the device info into device attr,
    292		 * hid desc and report desc
    293		 */
    294		mousevsc_on_receive_device_info(input_dev,
    295			(struct synthhid_device_info *)pipe_msg->data);
    296		break;
    297	case SYNTH_HID_INPUT_REPORT:
    298		input_report =
    299			(struct synthhid_input_report *)pipe_msg->data;
    300		if (!input_dev->init_complete)
    301			break;
    302
    303		len = min(input_report->header.size,
    304			  (u32)sizeof(input_dev->input_buf));
    305		memcpy(input_dev->input_buf, input_report->buffer, len);
    306		hid_input_report(input_dev->hid_device, HID_INPUT_REPORT,
    307				 input_dev->input_buf, len, 1);
    308
    309		pm_wakeup_hard_event(&input_dev->device->device);
    310
    311		break;
    312	default:
    313		pr_err("unsupported hid msg type - type %d len %d\n",
    314		       hid_msg->header.type, hid_msg->header.size);
    315		break;
    316	}
    317
    318}
    319
    320static void mousevsc_on_channel_callback(void *context)
    321{
    322	struct hv_device *device = context;
    323	struct vmpacket_descriptor *desc;
    324
    325	foreach_vmbus_pkt(desc, device->channel) {
    326		switch (desc->type) {
    327		case VM_PKT_COMP:
    328			break;
    329
    330		case VM_PKT_DATA_INBAND:
    331			mousevsc_on_receive(device, desc);
    332			break;
    333
    334		default:
    335			pr_err("Unhandled packet type %d, tid %llx len %d\n",
    336			       desc->type, desc->trans_id, desc->len8 * 8);
    337			break;
    338		}
    339	}
    340}
    341
    342static int mousevsc_connect_to_vsp(struct hv_device *device)
    343{
    344	int ret = 0;
    345	unsigned long t;
    346	struct mousevsc_dev *input_dev = hv_get_drvdata(device);
    347	struct mousevsc_prt_msg *request;
    348	struct mousevsc_prt_msg *response;
    349
    350	reinit_completion(&input_dev->wait_event);
    351
    352	request = &input_dev->protocol_req;
    353	memset(request, 0, sizeof(struct mousevsc_prt_msg));
    354
    355	request->type = PIPE_MESSAGE_DATA;
    356	request->size = sizeof(struct synthhid_protocol_request);
    357	request->request.header.type = SYNTH_HID_PROTOCOL_REQUEST;
    358	request->request.header.size = sizeof(unsigned int);
    359	request->request.version_requested.version = SYNTHHID_INPUT_VERSION;
    360
    361	ret = vmbus_sendpacket(device->channel, request,
    362				sizeof(struct pipe_prt_msg) -
    363				sizeof(unsigned char) +
    364				sizeof(struct synthhid_protocol_request),
    365				(unsigned long)request,
    366				VM_PKT_DATA_INBAND,
    367				VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
    368	if (ret)
    369		goto cleanup;
    370
    371	t = wait_for_completion_timeout(&input_dev->wait_event, 5*HZ);
    372	if (!t) {
    373		ret = -ETIMEDOUT;
    374		goto cleanup;
    375	}
    376
    377	response = &input_dev->protocol_resp;
    378
    379	if (!response->response.approved) {
    380		pr_err("synthhid protocol request failed (version %d)\n",
    381		       SYNTHHID_INPUT_VERSION);
    382		ret = -ENODEV;
    383		goto cleanup;
    384	}
    385
    386	t = wait_for_completion_timeout(&input_dev->wait_event, 5*HZ);
    387	if (!t) {
    388		ret = -ETIMEDOUT;
    389		goto cleanup;
    390	}
    391
    392	/*
    393	 * We should have gotten the device attr, hid desc and report
    394	 * desc at this point
    395	 */
    396	ret = input_dev->dev_info_status;
    397
    398cleanup:
    399	return ret;
    400}
    401
    402static int mousevsc_hid_parse(struct hid_device *hid)
    403{
    404	struct hv_device *dev = hid_get_drvdata(hid);
    405	struct mousevsc_dev *input_dev = hv_get_drvdata(dev);
    406
    407	return hid_parse_report(hid, input_dev->report_desc,
    408				input_dev->report_desc_size);
    409}
    410
    411static int mousevsc_hid_open(struct hid_device *hid)
    412{
    413	return 0;
    414}
    415
    416static int mousevsc_hid_start(struct hid_device *hid)
    417{
    418	return 0;
    419}
    420
    421static void mousevsc_hid_close(struct hid_device *hid)
    422{
    423}
    424
    425static void mousevsc_hid_stop(struct hid_device *hid)
    426{
    427}
    428
    429static int mousevsc_hid_raw_request(struct hid_device *hid,
    430				    unsigned char report_num,
    431				    __u8 *buf, size_t len,
    432				    unsigned char rtype,
    433				    int reqtype)
    434{
    435	return 0;
    436}
    437
    438static struct hid_ll_driver mousevsc_ll_driver = {
    439	.parse = mousevsc_hid_parse,
    440	.open = mousevsc_hid_open,
    441	.close = mousevsc_hid_close,
    442	.start = mousevsc_hid_start,
    443	.stop = mousevsc_hid_stop,
    444	.raw_request = mousevsc_hid_raw_request,
    445};
    446
    447static struct hid_driver mousevsc_hid_driver;
    448
    449static int mousevsc_probe(struct hv_device *device,
    450			const struct hv_vmbus_device_id *dev_id)
    451{
    452	int ret;
    453	struct mousevsc_dev *input_dev;
    454	struct hid_device *hid_dev;
    455
    456	input_dev = mousevsc_alloc_device(device);
    457
    458	if (!input_dev)
    459		return -ENOMEM;
    460
    461	ret = vmbus_open(device->channel,
    462		INPUTVSC_SEND_RING_BUFFER_SIZE,
    463		INPUTVSC_RECV_RING_BUFFER_SIZE,
    464		NULL,
    465		0,
    466		mousevsc_on_channel_callback,
    467		device
    468		);
    469
    470	if (ret)
    471		goto probe_err0;
    472
    473	ret = mousevsc_connect_to_vsp(device);
    474
    475	if (ret)
    476		goto probe_err1;
    477
    478	/* workaround SA-167 */
    479	if (input_dev->report_desc[14] == 0x25)
    480		input_dev->report_desc[14] = 0x29;
    481
    482	hid_dev = hid_allocate_device();
    483	if (IS_ERR(hid_dev)) {
    484		ret = PTR_ERR(hid_dev);
    485		goto probe_err1;
    486	}
    487
    488	hid_dev->ll_driver = &mousevsc_ll_driver;
    489	hid_dev->driver = &mousevsc_hid_driver;
    490	hid_dev->bus = BUS_VIRTUAL;
    491	hid_dev->vendor = input_dev->hid_dev_info.vendor;
    492	hid_dev->product = input_dev->hid_dev_info.product;
    493	hid_dev->version = input_dev->hid_dev_info.version;
    494	input_dev->hid_device = hid_dev;
    495
    496	sprintf(hid_dev->name, "%s", "Microsoft Vmbus HID-compliant Mouse");
    497
    498	hid_set_drvdata(hid_dev, device);
    499
    500	ret = hid_add_device(hid_dev);
    501	if (ret)
    502		goto probe_err1;
    503
    504
    505	ret = hid_parse(hid_dev);
    506	if (ret) {
    507		hid_err(hid_dev, "parse failed\n");
    508		goto probe_err2;
    509	}
    510
    511	ret = hid_hw_start(hid_dev, HID_CONNECT_HIDINPUT | HID_CONNECT_HIDDEV);
    512
    513	if (ret) {
    514		hid_err(hid_dev, "hw start failed\n");
    515		goto probe_err2;
    516	}
    517
    518	device_init_wakeup(&device->device, true);
    519
    520	input_dev->connected = true;
    521	input_dev->init_complete = true;
    522
    523	return ret;
    524
    525probe_err2:
    526	hid_destroy_device(hid_dev);
    527
    528probe_err1:
    529	vmbus_close(device->channel);
    530
    531probe_err0:
    532	mousevsc_free_device(input_dev);
    533
    534	return ret;
    535}
    536
    537
    538static int mousevsc_remove(struct hv_device *dev)
    539{
    540	struct mousevsc_dev *input_dev = hv_get_drvdata(dev);
    541
    542	device_init_wakeup(&dev->device, false);
    543	vmbus_close(dev->channel);
    544	hid_hw_stop(input_dev->hid_device);
    545	hid_destroy_device(input_dev->hid_device);
    546	mousevsc_free_device(input_dev);
    547
    548	return 0;
    549}
    550
    551static int mousevsc_suspend(struct hv_device *dev)
    552{
    553	vmbus_close(dev->channel);
    554
    555	return 0;
    556}
    557
    558static int mousevsc_resume(struct hv_device *dev)
    559{
    560	int ret;
    561
    562	ret = vmbus_open(dev->channel,
    563			 INPUTVSC_SEND_RING_BUFFER_SIZE,
    564			 INPUTVSC_RECV_RING_BUFFER_SIZE,
    565			 NULL, 0,
    566			 mousevsc_on_channel_callback,
    567			 dev);
    568	if (ret)
    569		return ret;
    570
    571	ret = mousevsc_connect_to_vsp(dev);
    572	return ret;
    573}
    574
    575static const struct hv_vmbus_device_id id_table[] = {
    576	/* Mouse guid */
    577	{ HV_MOUSE_GUID, },
    578	{ },
    579};
    580
    581MODULE_DEVICE_TABLE(vmbus, id_table);
    582
    583static struct  hv_driver mousevsc_drv = {
    584	.name = KBUILD_MODNAME,
    585	.id_table = id_table,
    586	.probe = mousevsc_probe,
    587	.remove = mousevsc_remove,
    588	.suspend = mousevsc_suspend,
    589	.resume = mousevsc_resume,
    590	.driver = {
    591		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
    592	},
    593};
    594
    595static int __init mousevsc_init(void)
    596{
    597	return vmbus_driver_register(&mousevsc_drv);
    598}
    599
    600static void __exit mousevsc_exit(void)
    601{
    602	vmbus_driver_unregister(&mousevsc_drv);
    603}
    604
    605MODULE_LICENSE("GPL");
    606MODULE_DESCRIPTION("Microsoft Hyper-V Synthetic HID Driver");
    607
    608module_init(mousevsc_init);
    609module_exit(mousevsc_exit);