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

userio.c (6678B)


      1/*
      2 * userio kernel serio device emulation module
      3 * Copyright (C) 2015 Red Hat
      4 * Copyright (C) 2015 Stephen Chandler Paul <thatslyude@gmail.com>
      5 *
      6 * This program is free software; you can redistribute it and/or modify it
      7 * under the terms of the GNU Lesser General Public License as published by
      8 * the Free Software Foundation; either version 2 of the License, or (at
      9 * your option) any later version.
     10 *
     11 * This program is distributed in the hope that it will be useful, but
     12 * WITHOUT ANY WARRANTY; without even the implied warranty of
     13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
     14 * General Public License for more details.
     15 */
     16
     17#include <linux/circ_buf.h>
     18#include <linux/mutex.h>
     19#include <linux/module.h>
     20#include <linux/init.h>
     21#include <linux/kernel.h>
     22#include <linux/serio.h>
     23#include <linux/slab.h>
     24#include <linux/fs.h>
     25#include <linux/miscdevice.h>
     26#include <linux/sched.h>
     27#include <linux/poll.h>
     28#include <uapi/linux/userio.h>
     29
     30#define USERIO_NAME		"userio"
     31#define USERIO_BUFSIZE		16
     32
     33static struct miscdevice userio_misc;
     34
     35struct userio_device {
     36	struct serio *serio;
     37	struct mutex mutex;
     38
     39	bool running;
     40
     41	u8 head;
     42	u8 tail;
     43
     44	spinlock_t buf_lock;
     45	unsigned char buf[USERIO_BUFSIZE];
     46
     47	wait_queue_head_t waitq;
     48};
     49
     50/**
     51 * userio_device_write - Write data from serio to a userio device in userspace
     52 * @id: The serio port for the userio device
     53 * @val: The data to write to the device
     54 */
     55static int userio_device_write(struct serio *id, unsigned char val)
     56{
     57	struct userio_device *userio = id->port_data;
     58	unsigned long flags;
     59
     60	spin_lock_irqsave(&userio->buf_lock, flags);
     61
     62	userio->buf[userio->head] = val;
     63	userio->head = (userio->head + 1) % USERIO_BUFSIZE;
     64
     65	if (userio->head == userio->tail)
     66		dev_warn(userio_misc.this_device,
     67			 "Buffer overflowed, userio client isn't keeping up");
     68
     69	spin_unlock_irqrestore(&userio->buf_lock, flags);
     70
     71	wake_up_interruptible(&userio->waitq);
     72
     73	return 0;
     74}
     75
     76static int userio_char_open(struct inode *inode, struct file *file)
     77{
     78	struct userio_device *userio;
     79
     80	userio = kzalloc(sizeof(struct userio_device), GFP_KERNEL);
     81	if (!userio)
     82		return -ENOMEM;
     83
     84	mutex_init(&userio->mutex);
     85	spin_lock_init(&userio->buf_lock);
     86	init_waitqueue_head(&userio->waitq);
     87
     88	userio->serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
     89	if (!userio->serio) {
     90		kfree(userio);
     91		return -ENOMEM;
     92	}
     93
     94	userio->serio->write = userio_device_write;
     95	userio->serio->port_data = userio;
     96
     97	file->private_data = userio;
     98
     99	return 0;
    100}
    101
    102static int userio_char_release(struct inode *inode, struct file *file)
    103{
    104	struct userio_device *userio = file->private_data;
    105
    106	if (userio->running) {
    107		/*
    108		 * Don't free the serio port here, serio_unregister_port()
    109		 * does it for us.
    110		 */
    111		serio_unregister_port(userio->serio);
    112	} else {
    113		kfree(userio->serio);
    114	}
    115
    116	kfree(userio);
    117
    118	return 0;
    119}
    120
    121static ssize_t userio_char_read(struct file *file, char __user *user_buffer,
    122				size_t count, loff_t *ppos)
    123{
    124	struct userio_device *userio = file->private_data;
    125	int error;
    126	size_t nonwrap_len, copylen;
    127	unsigned char buf[USERIO_BUFSIZE];
    128	unsigned long flags;
    129
    130	/*
    131	 * By the time we get here, the data that was waiting might have
    132	 * been taken by another thread. Grab the buffer lock and check if
    133	 * there's still any data waiting, otherwise repeat this process
    134	 * until we have data (unless the file descriptor is non-blocking
    135	 * of course).
    136	 */
    137	for (;;) {
    138		spin_lock_irqsave(&userio->buf_lock, flags);
    139
    140		nonwrap_len = CIRC_CNT_TO_END(userio->head,
    141					      userio->tail,
    142					      USERIO_BUFSIZE);
    143		copylen = min(nonwrap_len, count);
    144		if (copylen) {
    145			memcpy(buf, &userio->buf[userio->tail], copylen);
    146			userio->tail = (userio->tail + copylen) %
    147							USERIO_BUFSIZE;
    148		}
    149
    150		spin_unlock_irqrestore(&userio->buf_lock, flags);
    151
    152		if (nonwrap_len)
    153			break;
    154
    155		/* buffer was/is empty */
    156		if (file->f_flags & O_NONBLOCK)
    157			return -EAGAIN;
    158
    159		/*
    160		 * count == 0 is special - no IO is done but we check
    161		 * for error conditions (see above).
    162		 */
    163		if (count == 0)
    164			return 0;
    165
    166		error = wait_event_interruptible(userio->waitq,
    167						 userio->head != userio->tail);
    168		if (error)
    169			return error;
    170	}
    171
    172	if (copylen)
    173		if (copy_to_user(user_buffer, buf, copylen))
    174			return -EFAULT;
    175
    176	return copylen;
    177}
    178
    179static ssize_t userio_char_write(struct file *file, const char __user *buffer,
    180				 size_t count, loff_t *ppos)
    181{
    182	struct userio_device *userio = file->private_data;
    183	struct userio_cmd cmd;
    184	int error;
    185
    186	if (count != sizeof(cmd)) {
    187		dev_warn(userio_misc.this_device, "Invalid payload size\n");
    188		return -EINVAL;
    189	}
    190
    191	if (copy_from_user(&cmd, buffer, sizeof(cmd)))
    192		return -EFAULT;
    193
    194	error = mutex_lock_interruptible(&userio->mutex);
    195	if (error)
    196		return error;
    197
    198	switch (cmd.type) {
    199	case USERIO_CMD_REGISTER:
    200		if (!userio->serio->id.type) {
    201			dev_warn(userio_misc.this_device,
    202				 "No port type given on /dev/userio\n");
    203
    204			error = -EINVAL;
    205			goto out;
    206		}
    207
    208		if (userio->running) {
    209			dev_warn(userio_misc.this_device,
    210				 "Begin command sent, but we're already running\n");
    211			error = -EBUSY;
    212			goto out;
    213		}
    214
    215		userio->running = true;
    216		serio_register_port(userio->serio);
    217		break;
    218
    219	case USERIO_CMD_SET_PORT_TYPE:
    220		if (userio->running) {
    221			dev_warn(userio_misc.this_device,
    222				 "Can't change port type on an already running userio instance\n");
    223			error = -EBUSY;
    224			goto out;
    225		}
    226
    227		userio->serio->id.type = cmd.data;
    228		break;
    229
    230	case USERIO_CMD_SEND_INTERRUPT:
    231		if (!userio->running) {
    232			dev_warn(userio_misc.this_device,
    233				 "The device must be registered before sending interrupts\n");
    234			error = -ENODEV;
    235			goto out;
    236		}
    237
    238		serio_interrupt(userio->serio, cmd.data, 0);
    239		break;
    240
    241	default:
    242		error = -EOPNOTSUPP;
    243		goto out;
    244	}
    245
    246out:
    247	mutex_unlock(&userio->mutex);
    248	return error ?: count;
    249}
    250
    251static __poll_t userio_char_poll(struct file *file, poll_table *wait)
    252{
    253	struct userio_device *userio = file->private_data;
    254
    255	poll_wait(file, &userio->waitq, wait);
    256
    257	if (userio->head != userio->tail)
    258		return EPOLLIN | EPOLLRDNORM;
    259
    260	return 0;
    261}
    262
    263static const struct file_operations userio_fops = {
    264	.owner		= THIS_MODULE,
    265	.open		= userio_char_open,
    266	.release	= userio_char_release,
    267	.read		= userio_char_read,
    268	.write		= userio_char_write,
    269	.poll		= userio_char_poll,
    270	.llseek		= no_llseek,
    271};
    272
    273static struct miscdevice userio_misc = {
    274	.fops	= &userio_fops,
    275	.minor	= USERIO_MINOR,
    276	.name	= USERIO_NAME,
    277};
    278module_driver(userio_misc, misc_register, misc_deregister);
    279
    280MODULE_ALIAS_MISCDEV(USERIO_MINOR);
    281MODULE_ALIAS("devname:" USERIO_NAME);
    282
    283MODULE_AUTHOR("Stephen Chandler Paul <thatslyude@gmail.com>");
    284MODULE_DESCRIPTION("Virtual Serio Device Support");
    285MODULE_LICENSE("GPL");