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

pps.c (11268B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * PPS core file
      4 *
      5 * Copyright (C) 2005-2009   Rodolfo Giometti <giometti@linux.it>
      6 */
      7
      8#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
      9
     10#include <linux/kernel.h>
     11#include <linux/module.h>
     12#include <linux/init.h>
     13#include <linux/sched.h>
     14#include <linux/uaccess.h>
     15#include <linux/idr.h>
     16#include <linux/mutex.h>
     17#include <linux/cdev.h>
     18#include <linux/poll.h>
     19#include <linux/pps_kernel.h>
     20#include <linux/slab.h>
     21
     22#include "kc.h"
     23
     24/*
     25 * Local variables
     26 */
     27
     28static dev_t pps_devt;
     29static struct class *pps_class;
     30
     31static DEFINE_MUTEX(pps_idr_lock);
     32static DEFINE_IDR(pps_idr);
     33
     34/*
     35 * Char device methods
     36 */
     37
     38static __poll_t pps_cdev_poll(struct file *file, poll_table *wait)
     39{
     40	struct pps_device *pps = file->private_data;
     41
     42	poll_wait(file, &pps->queue, wait);
     43
     44	return EPOLLIN | EPOLLRDNORM;
     45}
     46
     47static int pps_cdev_fasync(int fd, struct file *file, int on)
     48{
     49	struct pps_device *pps = file->private_data;
     50	return fasync_helper(fd, file, on, &pps->async_queue);
     51}
     52
     53static int pps_cdev_pps_fetch(struct pps_device *pps, struct pps_fdata *fdata)
     54{
     55	unsigned int ev = pps->last_ev;
     56	int err = 0;
     57
     58	/* Manage the timeout */
     59	if (fdata->timeout.flags & PPS_TIME_INVALID)
     60		err = wait_event_interruptible(pps->queue,
     61				ev != pps->last_ev);
     62	else {
     63		unsigned long ticks;
     64
     65		dev_dbg(pps->dev, "timeout %lld.%09d\n",
     66				(long long) fdata->timeout.sec,
     67				fdata->timeout.nsec);
     68		ticks = fdata->timeout.sec * HZ;
     69		ticks += fdata->timeout.nsec / (NSEC_PER_SEC / HZ);
     70
     71		if (ticks != 0) {
     72			err = wait_event_interruptible_timeout(
     73					pps->queue,
     74					ev != pps->last_ev,
     75					ticks);
     76			if (err == 0)
     77				return -ETIMEDOUT;
     78		}
     79	}
     80
     81	/* Check for pending signals */
     82	if (err == -ERESTARTSYS) {
     83		dev_dbg(pps->dev, "pending signal caught\n");
     84		return -EINTR;
     85	}
     86
     87	return 0;
     88}
     89
     90static long pps_cdev_ioctl(struct file *file,
     91		unsigned int cmd, unsigned long arg)
     92{
     93	struct pps_device *pps = file->private_data;
     94	struct pps_kparams params;
     95	void __user *uarg = (void __user *) arg;
     96	int __user *iuarg = (int __user *) arg;
     97	int err;
     98
     99	switch (cmd) {
    100	case PPS_GETPARAMS:
    101		dev_dbg(pps->dev, "PPS_GETPARAMS\n");
    102
    103		spin_lock_irq(&pps->lock);
    104
    105		/* Get the current parameters */
    106		params = pps->params;
    107
    108		spin_unlock_irq(&pps->lock);
    109
    110		err = copy_to_user(uarg, &params, sizeof(struct pps_kparams));
    111		if (err)
    112			return -EFAULT;
    113
    114		break;
    115
    116	case PPS_SETPARAMS:
    117		dev_dbg(pps->dev, "PPS_SETPARAMS\n");
    118
    119		/* Check the capabilities */
    120		if (!capable(CAP_SYS_TIME))
    121			return -EPERM;
    122
    123		err = copy_from_user(&params, uarg, sizeof(struct pps_kparams));
    124		if (err)
    125			return -EFAULT;
    126		if (!(params.mode & (PPS_CAPTUREASSERT | PPS_CAPTURECLEAR))) {
    127			dev_dbg(pps->dev, "capture mode unspecified (%x)\n",
    128								params.mode);
    129			return -EINVAL;
    130		}
    131
    132		/* Check for supported capabilities */
    133		if ((params.mode & ~pps->info.mode) != 0) {
    134			dev_dbg(pps->dev, "unsupported capabilities (%x)\n",
    135								params.mode);
    136			return -EINVAL;
    137		}
    138
    139		spin_lock_irq(&pps->lock);
    140
    141		/* Save the new parameters */
    142		pps->params = params;
    143
    144		/* Restore the read only parameters */
    145		if ((params.mode & (PPS_TSFMT_TSPEC | PPS_TSFMT_NTPFP)) == 0) {
    146			/* section 3.3 of RFC 2783 interpreted */
    147			dev_dbg(pps->dev, "time format unspecified (%x)\n",
    148								params.mode);
    149			pps->params.mode |= PPS_TSFMT_TSPEC;
    150		}
    151		if (pps->info.mode & PPS_CANWAIT)
    152			pps->params.mode |= PPS_CANWAIT;
    153		pps->params.api_version = PPS_API_VERS;
    154
    155		/*
    156		 * Clear unused fields of pps_kparams to avoid leaking
    157		 * uninitialized data of the PPS_SETPARAMS caller via
    158		 * PPS_GETPARAMS
    159		 */
    160		pps->params.assert_off_tu.flags = 0;
    161		pps->params.clear_off_tu.flags = 0;
    162
    163		spin_unlock_irq(&pps->lock);
    164
    165		break;
    166
    167	case PPS_GETCAP:
    168		dev_dbg(pps->dev, "PPS_GETCAP\n");
    169
    170		err = put_user(pps->info.mode, iuarg);
    171		if (err)
    172			return -EFAULT;
    173
    174		break;
    175
    176	case PPS_FETCH: {
    177		struct pps_fdata fdata;
    178
    179		dev_dbg(pps->dev, "PPS_FETCH\n");
    180
    181		err = copy_from_user(&fdata, uarg, sizeof(struct pps_fdata));
    182		if (err)
    183			return -EFAULT;
    184
    185		err = pps_cdev_pps_fetch(pps, &fdata);
    186		if (err)
    187			return err;
    188
    189		/* Return the fetched timestamp */
    190		spin_lock_irq(&pps->lock);
    191
    192		fdata.info.assert_sequence = pps->assert_sequence;
    193		fdata.info.clear_sequence = pps->clear_sequence;
    194		fdata.info.assert_tu = pps->assert_tu;
    195		fdata.info.clear_tu = pps->clear_tu;
    196		fdata.info.current_mode = pps->current_mode;
    197
    198		spin_unlock_irq(&pps->lock);
    199
    200		err = copy_to_user(uarg, &fdata, sizeof(struct pps_fdata));
    201		if (err)
    202			return -EFAULT;
    203
    204		break;
    205	}
    206	case PPS_KC_BIND: {
    207		struct pps_bind_args bind_args;
    208
    209		dev_dbg(pps->dev, "PPS_KC_BIND\n");
    210
    211		/* Check the capabilities */
    212		if (!capable(CAP_SYS_TIME))
    213			return -EPERM;
    214
    215		if (copy_from_user(&bind_args, uarg,
    216					sizeof(struct pps_bind_args)))
    217			return -EFAULT;
    218
    219		/* Check for supported capabilities */
    220		if ((bind_args.edge & ~pps->info.mode) != 0) {
    221			dev_err(pps->dev, "unsupported capabilities (%x)\n",
    222					bind_args.edge);
    223			return -EINVAL;
    224		}
    225
    226		/* Validate parameters roughly */
    227		if (bind_args.tsformat != PPS_TSFMT_TSPEC ||
    228				(bind_args.edge & ~PPS_CAPTUREBOTH) != 0 ||
    229				bind_args.consumer != PPS_KC_HARDPPS) {
    230			dev_err(pps->dev, "invalid kernel consumer bind"
    231					" parameters (%x)\n", bind_args.edge);
    232			return -EINVAL;
    233		}
    234
    235		err = pps_kc_bind(pps, &bind_args);
    236		if (err < 0)
    237			return err;
    238
    239		break;
    240	}
    241	default:
    242		return -ENOTTY;
    243	}
    244
    245	return 0;
    246}
    247
    248#ifdef CONFIG_COMPAT
    249static long pps_cdev_compat_ioctl(struct file *file,
    250		unsigned int cmd, unsigned long arg)
    251{
    252	struct pps_device *pps = file->private_data;
    253	void __user *uarg = (void __user *) arg;
    254
    255	cmd = _IOC(_IOC_DIR(cmd), _IOC_TYPE(cmd), _IOC_NR(cmd), sizeof(void *));
    256
    257	if (cmd == PPS_FETCH) {
    258		struct pps_fdata_compat compat;
    259		struct pps_fdata fdata;
    260		int err;
    261
    262		dev_dbg(pps->dev, "PPS_FETCH\n");
    263
    264		err = copy_from_user(&compat, uarg, sizeof(struct pps_fdata_compat));
    265		if (err)
    266			return -EFAULT;
    267
    268		memcpy(&fdata.timeout, &compat.timeout,
    269					sizeof(struct pps_ktime_compat));
    270
    271		err = pps_cdev_pps_fetch(pps, &fdata);
    272		if (err)
    273			return err;
    274
    275		/* Return the fetched timestamp */
    276		spin_lock_irq(&pps->lock);
    277
    278		compat.info.assert_sequence = pps->assert_sequence;
    279		compat.info.clear_sequence = pps->clear_sequence;
    280		compat.info.current_mode = pps->current_mode;
    281
    282		memcpy(&compat.info.assert_tu, &pps->assert_tu,
    283				sizeof(struct pps_ktime_compat));
    284		memcpy(&compat.info.clear_tu, &pps->clear_tu,
    285				sizeof(struct pps_ktime_compat));
    286
    287		spin_unlock_irq(&pps->lock);
    288
    289		return copy_to_user(uarg, &compat,
    290				sizeof(struct pps_fdata_compat)) ? -EFAULT : 0;
    291	}
    292
    293	return pps_cdev_ioctl(file, cmd, arg);
    294}
    295#else
    296#define pps_cdev_compat_ioctl	NULL
    297#endif
    298
    299static int pps_cdev_open(struct inode *inode, struct file *file)
    300{
    301	struct pps_device *pps = container_of(inode->i_cdev,
    302						struct pps_device, cdev);
    303	file->private_data = pps;
    304	kobject_get(&pps->dev->kobj);
    305	return 0;
    306}
    307
    308static int pps_cdev_release(struct inode *inode, struct file *file)
    309{
    310	struct pps_device *pps = container_of(inode->i_cdev,
    311						struct pps_device, cdev);
    312	kobject_put(&pps->dev->kobj);
    313	return 0;
    314}
    315
    316/*
    317 * Char device stuff
    318 */
    319
    320static const struct file_operations pps_cdev_fops = {
    321	.owner		= THIS_MODULE,
    322	.llseek		= no_llseek,
    323	.poll		= pps_cdev_poll,
    324	.fasync		= pps_cdev_fasync,
    325	.compat_ioctl	= pps_cdev_compat_ioctl,
    326	.unlocked_ioctl	= pps_cdev_ioctl,
    327	.open		= pps_cdev_open,
    328	.release	= pps_cdev_release,
    329};
    330
    331static void pps_device_destruct(struct device *dev)
    332{
    333	struct pps_device *pps = dev_get_drvdata(dev);
    334
    335	cdev_del(&pps->cdev);
    336
    337	/* Now we can release the ID for re-use */
    338	pr_debug("deallocating pps%d\n", pps->id);
    339	mutex_lock(&pps_idr_lock);
    340	idr_remove(&pps_idr, pps->id);
    341	mutex_unlock(&pps_idr_lock);
    342
    343	kfree(dev);
    344	kfree(pps);
    345}
    346
    347int pps_register_cdev(struct pps_device *pps)
    348{
    349	int err;
    350	dev_t devt;
    351
    352	mutex_lock(&pps_idr_lock);
    353	/*
    354	 * Get new ID for the new PPS source.  After idr_alloc() calling
    355	 * the new source will be freely available into the kernel.
    356	 */
    357	err = idr_alloc(&pps_idr, pps, 0, PPS_MAX_SOURCES, GFP_KERNEL);
    358	if (err < 0) {
    359		if (err == -ENOSPC) {
    360			pr_err("%s: too many PPS sources in the system\n",
    361			       pps->info.name);
    362			err = -EBUSY;
    363		}
    364		goto out_unlock;
    365	}
    366	pps->id = err;
    367	mutex_unlock(&pps_idr_lock);
    368
    369	devt = MKDEV(MAJOR(pps_devt), pps->id);
    370
    371	cdev_init(&pps->cdev, &pps_cdev_fops);
    372	pps->cdev.owner = pps->info.owner;
    373
    374	err = cdev_add(&pps->cdev, devt, 1);
    375	if (err) {
    376		pr_err("%s: failed to add char device %d:%d\n",
    377				pps->info.name, MAJOR(pps_devt), pps->id);
    378		goto free_idr;
    379	}
    380	pps->dev = device_create(pps_class, pps->info.dev, devt, pps,
    381							"pps%d", pps->id);
    382	if (IS_ERR(pps->dev)) {
    383		err = PTR_ERR(pps->dev);
    384		goto del_cdev;
    385	}
    386
    387	/* Override the release function with our own */
    388	pps->dev->release = pps_device_destruct;
    389
    390	pr_debug("source %s got cdev (%d:%d)\n", pps->info.name,
    391			MAJOR(pps_devt), pps->id);
    392
    393	return 0;
    394
    395del_cdev:
    396	cdev_del(&pps->cdev);
    397
    398free_idr:
    399	mutex_lock(&pps_idr_lock);
    400	idr_remove(&pps_idr, pps->id);
    401out_unlock:
    402	mutex_unlock(&pps_idr_lock);
    403	return err;
    404}
    405
    406void pps_unregister_cdev(struct pps_device *pps)
    407{
    408	pr_debug("unregistering pps%d\n", pps->id);
    409	pps->lookup_cookie = NULL;
    410	device_destroy(pps_class, pps->dev->devt);
    411}
    412
    413/*
    414 * Look up a pps device by magic cookie.
    415 * The cookie is usually a pointer to some enclosing device, but this
    416 * code doesn't care; you should never be dereferencing it.
    417 *
    418 * This is a bit of a kludge that is currently used only by the PPS
    419 * serial line discipline.  It may need to be tweaked when a second user
    420 * is found.
    421 *
    422 * There is no function interface for setting the lookup_cookie field.
    423 * It's initialized to NULL when the pps device is created, and if a
    424 * client wants to use it, just fill it in afterward.
    425 *
    426 * The cookie is automatically set to NULL in pps_unregister_source()
    427 * so that it will not be used again, even if the pps device cannot
    428 * be removed from the idr due to pending references holding the minor
    429 * number in use.
    430 */
    431struct pps_device *pps_lookup_dev(void const *cookie)
    432{
    433	struct pps_device *pps;
    434	unsigned id;
    435
    436	rcu_read_lock();
    437	idr_for_each_entry(&pps_idr, pps, id)
    438		if (cookie == pps->lookup_cookie)
    439			break;
    440	rcu_read_unlock();
    441	return pps;
    442}
    443EXPORT_SYMBOL(pps_lookup_dev);
    444
    445/*
    446 * Module stuff
    447 */
    448
    449static void __exit pps_exit(void)
    450{
    451	class_destroy(pps_class);
    452	unregister_chrdev_region(pps_devt, PPS_MAX_SOURCES);
    453}
    454
    455static int __init pps_init(void)
    456{
    457	int err;
    458
    459	pps_class = class_create(THIS_MODULE, "pps");
    460	if (IS_ERR(pps_class)) {
    461		pr_err("failed to allocate class\n");
    462		return PTR_ERR(pps_class);
    463	}
    464	pps_class->dev_groups = pps_groups;
    465
    466	err = alloc_chrdev_region(&pps_devt, 0, PPS_MAX_SOURCES, "pps");
    467	if (err < 0) {
    468		pr_err("failed to allocate char device region\n");
    469		goto remove_class;
    470	}
    471
    472	pr_info("LinuxPPS API ver. %d registered\n", PPS_API_VERS);
    473	pr_info("Software ver. %s - Copyright 2005-2007 Rodolfo Giometti "
    474		"<giometti@linux.it>\n", PPS_VERSION);
    475
    476	return 0;
    477
    478remove_class:
    479	class_destroy(pps_class);
    480
    481	return err;
    482}
    483
    484subsys_initcall(pps_init);
    485module_exit(pps_exit);
    486
    487MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
    488MODULE_DESCRIPTION("LinuxPPS support (RFC 2783) - ver. " PPS_VERSION);
    489MODULE_LICENSE("GPL");