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

phantom.c (13329B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *  Copyright (C) 2005-2007 Jiri Slaby <jirislaby@gmail.com>
      4 *
      5 *  You need a userspace library to cooperate with this driver. It (and other
      6 *  info) may be obtained here:
      7 *  http://www.fi.muni.cz/~xslaby/phantom.html
      8 *  or alternatively, you might use OpenHaptics provided by Sensable.
      9 */
     10
     11#include <linux/compat.h>
     12#include <linux/kernel.h>
     13#include <linux/module.h>
     14#include <linux/device.h>
     15#include <linux/pci.h>
     16#include <linux/fs.h>
     17#include <linux/poll.h>
     18#include <linux/interrupt.h>
     19#include <linux/cdev.h>
     20#include <linux/slab.h>
     21#include <linux/phantom.h>
     22#include <linux/sched.h>
     23#include <linux/mutex.h>
     24
     25#include <linux/atomic.h>
     26#include <asm/io.h>
     27
     28#define PHANTOM_VERSION		"n0.9.8"
     29
     30#define PHANTOM_MAX_MINORS	8
     31
     32#define PHN_IRQCTL		0x4c    /* irq control in caddr space */
     33
     34#define PHB_RUNNING		1
     35#define PHB_NOT_OH		2
     36
     37static DEFINE_MUTEX(phantom_mutex);
     38static struct class *phantom_class;
     39static int phantom_major;
     40
     41struct phantom_device {
     42	unsigned int opened;
     43	void __iomem *caddr;
     44	u32 __iomem *iaddr;
     45	u32 __iomem *oaddr;
     46	unsigned long status;
     47	atomic_t counter;
     48
     49	wait_queue_head_t wait;
     50	struct cdev cdev;
     51
     52	struct mutex open_lock;
     53	spinlock_t regs_lock;
     54
     55	/* used in NOT_OH mode */
     56	struct phm_regs oregs;
     57	u32 ctl_reg;
     58};
     59
     60static unsigned char phantom_devices[PHANTOM_MAX_MINORS];
     61
     62static int phantom_status(struct phantom_device *dev, unsigned long newstat)
     63{
     64	pr_debug("phantom_status %lx %lx\n", dev->status, newstat);
     65
     66	if (!(dev->status & PHB_RUNNING) && (newstat & PHB_RUNNING)) {
     67		atomic_set(&dev->counter, 0);
     68		iowrite32(PHN_CTL_IRQ, dev->iaddr + PHN_CONTROL);
     69		iowrite32(0x43, dev->caddr + PHN_IRQCTL);
     70		ioread32(dev->caddr + PHN_IRQCTL); /* PCI posting */
     71	} else if ((dev->status & PHB_RUNNING) && !(newstat & PHB_RUNNING)) {
     72		iowrite32(0, dev->caddr + PHN_IRQCTL);
     73		ioread32(dev->caddr + PHN_IRQCTL); /* PCI posting */
     74	}
     75
     76	dev->status = newstat;
     77
     78	return 0;
     79}
     80
     81/*
     82 * File ops
     83 */
     84
     85static long phantom_ioctl(struct file *file, unsigned int cmd,
     86		unsigned long arg)
     87{
     88	struct phantom_device *dev = file->private_data;
     89	struct phm_regs rs;
     90	struct phm_reg r;
     91	void __user *argp = (void __user *)arg;
     92	unsigned long flags;
     93	unsigned int i;
     94
     95	switch (cmd) {
     96	case PHN_SETREG:
     97	case PHN_SET_REG:
     98		if (copy_from_user(&r, argp, sizeof(r)))
     99			return -EFAULT;
    100
    101		if (r.reg > 7)
    102			return -EINVAL;
    103
    104		spin_lock_irqsave(&dev->regs_lock, flags);
    105		if (r.reg == PHN_CONTROL && (r.value & PHN_CTL_IRQ) &&
    106				phantom_status(dev, dev->status | PHB_RUNNING)){
    107			spin_unlock_irqrestore(&dev->regs_lock, flags);
    108			return -ENODEV;
    109		}
    110
    111		pr_debug("phantom: writing %x to %u\n", r.value, r.reg);
    112
    113		/* preserve amp bit (don't allow to change it when in NOT_OH) */
    114		if (r.reg == PHN_CONTROL && (dev->status & PHB_NOT_OH)) {
    115			r.value &= ~PHN_CTL_AMP;
    116			r.value |= dev->ctl_reg & PHN_CTL_AMP;
    117			dev->ctl_reg = r.value;
    118		}
    119
    120		iowrite32(r.value, dev->iaddr + r.reg);
    121		ioread32(dev->iaddr); /* PCI posting */
    122
    123		if (r.reg == PHN_CONTROL && !(r.value & PHN_CTL_IRQ))
    124			phantom_status(dev, dev->status & ~PHB_RUNNING);
    125		spin_unlock_irqrestore(&dev->regs_lock, flags);
    126		break;
    127	case PHN_SETREGS:
    128	case PHN_SET_REGS:
    129		if (copy_from_user(&rs, argp, sizeof(rs)))
    130			return -EFAULT;
    131
    132		pr_debug("phantom: SRS %u regs %x\n", rs.count, rs.mask);
    133		spin_lock_irqsave(&dev->regs_lock, flags);
    134		if (dev->status & PHB_NOT_OH)
    135			memcpy(&dev->oregs, &rs, sizeof(rs));
    136		else {
    137			u32 m = min(rs.count, 8U);
    138			for (i = 0; i < m; i++)
    139				if (rs.mask & BIT(i))
    140					iowrite32(rs.values[i], dev->oaddr + i);
    141			ioread32(dev->iaddr); /* PCI posting */
    142		}
    143		spin_unlock_irqrestore(&dev->regs_lock, flags);
    144		break;
    145	case PHN_GETREG:
    146	case PHN_GET_REG:
    147		if (copy_from_user(&r, argp, sizeof(r)))
    148			return -EFAULT;
    149
    150		if (r.reg > 7)
    151			return -EINVAL;
    152
    153		r.value = ioread32(dev->iaddr + r.reg);
    154
    155		if (copy_to_user(argp, &r, sizeof(r)))
    156			return -EFAULT;
    157		break;
    158	case PHN_GETREGS:
    159	case PHN_GET_REGS: {
    160		u32 m;
    161
    162		if (copy_from_user(&rs, argp, sizeof(rs)))
    163			return -EFAULT;
    164
    165		m = min(rs.count, 8U);
    166
    167		pr_debug("phantom: GRS %u regs %x\n", rs.count, rs.mask);
    168		spin_lock_irqsave(&dev->regs_lock, flags);
    169		for (i = 0; i < m; i++)
    170			if (rs.mask & BIT(i))
    171				rs.values[i] = ioread32(dev->iaddr + i);
    172		atomic_set(&dev->counter, 0);
    173		spin_unlock_irqrestore(&dev->regs_lock, flags);
    174
    175		if (copy_to_user(argp, &rs, sizeof(rs)))
    176			return -EFAULT;
    177		break;
    178	} case PHN_NOT_OH:
    179		spin_lock_irqsave(&dev->regs_lock, flags);
    180		if (dev->status & PHB_RUNNING) {
    181			printk(KERN_ERR "phantom: you need to set NOT_OH "
    182					"before you start the device!\n");
    183			spin_unlock_irqrestore(&dev->regs_lock, flags);
    184			return -EINVAL;
    185		}
    186		dev->status |= PHB_NOT_OH;
    187		spin_unlock_irqrestore(&dev->regs_lock, flags);
    188		break;
    189	default:
    190		return -ENOTTY;
    191	}
    192
    193	return 0;
    194}
    195
    196#ifdef CONFIG_COMPAT
    197static long phantom_compat_ioctl(struct file *filp, unsigned int cmd,
    198		unsigned long arg)
    199{
    200	if (_IOC_NR(cmd) <= 3 && _IOC_SIZE(cmd) == sizeof(compat_uptr_t)) {
    201		cmd &= ~(_IOC_SIZEMASK << _IOC_SIZESHIFT);
    202		cmd |= sizeof(void *) << _IOC_SIZESHIFT;
    203	}
    204	return phantom_ioctl(filp, cmd, (unsigned long)compat_ptr(arg));
    205}
    206#else
    207#define phantom_compat_ioctl NULL
    208#endif
    209
    210static int phantom_open(struct inode *inode, struct file *file)
    211{
    212	struct phantom_device *dev = container_of(inode->i_cdev,
    213			struct phantom_device, cdev);
    214
    215	mutex_lock(&phantom_mutex);
    216	nonseekable_open(inode, file);
    217
    218	if (mutex_lock_interruptible(&dev->open_lock)) {
    219		mutex_unlock(&phantom_mutex);
    220		return -ERESTARTSYS;
    221	}
    222
    223	if (dev->opened) {
    224		mutex_unlock(&dev->open_lock);
    225		mutex_unlock(&phantom_mutex);
    226		return -EINVAL;
    227	}
    228
    229	WARN_ON(dev->status & PHB_NOT_OH);
    230
    231	file->private_data = dev;
    232
    233	atomic_set(&dev->counter, 0);
    234	dev->opened++;
    235	mutex_unlock(&dev->open_lock);
    236	mutex_unlock(&phantom_mutex);
    237	return 0;
    238}
    239
    240static int phantom_release(struct inode *inode, struct file *file)
    241{
    242	struct phantom_device *dev = file->private_data;
    243
    244	mutex_lock(&dev->open_lock);
    245
    246	dev->opened = 0;
    247	phantom_status(dev, dev->status & ~PHB_RUNNING);
    248	dev->status &= ~PHB_NOT_OH;
    249
    250	mutex_unlock(&dev->open_lock);
    251
    252	return 0;
    253}
    254
    255static __poll_t phantom_poll(struct file *file, poll_table *wait)
    256{
    257	struct phantom_device *dev = file->private_data;
    258	__poll_t mask = 0;
    259
    260	pr_debug("phantom_poll: %d\n", atomic_read(&dev->counter));
    261	poll_wait(file, &dev->wait, wait);
    262
    263	if (!(dev->status & PHB_RUNNING))
    264		mask = EPOLLERR;
    265	else if (atomic_read(&dev->counter))
    266		mask = EPOLLIN | EPOLLRDNORM;
    267
    268	pr_debug("phantom_poll end: %x/%d\n", mask, atomic_read(&dev->counter));
    269
    270	return mask;
    271}
    272
    273static const struct file_operations phantom_file_ops = {
    274	.open = phantom_open,
    275	.release = phantom_release,
    276	.unlocked_ioctl = phantom_ioctl,
    277	.compat_ioctl = phantom_compat_ioctl,
    278	.poll = phantom_poll,
    279	.llseek = no_llseek,
    280};
    281
    282static irqreturn_t phantom_isr(int irq, void *data)
    283{
    284	struct phantom_device *dev = data;
    285	unsigned int i;
    286	u32 ctl;
    287
    288	spin_lock(&dev->regs_lock);
    289	ctl = ioread32(dev->iaddr + PHN_CONTROL);
    290	if (!(ctl & PHN_CTL_IRQ)) {
    291		spin_unlock(&dev->regs_lock);
    292		return IRQ_NONE;
    293	}
    294
    295	iowrite32(0, dev->iaddr);
    296	iowrite32(0xc0, dev->iaddr);
    297
    298	if (dev->status & PHB_NOT_OH) {
    299		struct phm_regs *r = &dev->oregs;
    300		u32 m = min(r->count, 8U);
    301
    302		for (i = 0; i < m; i++)
    303			if (r->mask & BIT(i))
    304				iowrite32(r->values[i], dev->oaddr + i);
    305
    306		dev->ctl_reg ^= PHN_CTL_AMP;
    307		iowrite32(dev->ctl_reg, dev->iaddr + PHN_CONTROL);
    308	}
    309	spin_unlock(&dev->regs_lock);
    310
    311	ioread32(dev->iaddr); /* PCI posting */
    312
    313	atomic_inc(&dev->counter);
    314	wake_up_interruptible(&dev->wait);
    315
    316	return IRQ_HANDLED;
    317}
    318
    319/*
    320 * Init and deinit driver
    321 */
    322
    323static unsigned int phantom_get_free(void)
    324{
    325	unsigned int i;
    326
    327	for (i = 0; i < PHANTOM_MAX_MINORS; i++)
    328		if (phantom_devices[i] == 0)
    329			break;
    330
    331	return i;
    332}
    333
    334static int phantom_probe(struct pci_dev *pdev,
    335	const struct pci_device_id *pci_id)
    336{
    337	struct phantom_device *pht;
    338	unsigned int minor;
    339	int retval;
    340
    341	retval = pci_enable_device(pdev);
    342	if (retval) {
    343		dev_err(&pdev->dev, "pci_enable_device failed!\n");
    344		goto err;
    345	}
    346
    347	minor = phantom_get_free();
    348	if (minor == PHANTOM_MAX_MINORS) {
    349		dev_err(&pdev->dev, "too many devices found!\n");
    350		retval = -EIO;
    351		goto err_dis;
    352	}
    353
    354	phantom_devices[minor] = 1;
    355
    356	retval = pci_request_regions(pdev, "phantom");
    357	if (retval) {
    358		dev_err(&pdev->dev, "pci_request_regions failed!\n");
    359		goto err_null;
    360	}
    361
    362	retval = -ENOMEM;
    363	pht = kzalloc(sizeof(*pht), GFP_KERNEL);
    364	if (pht == NULL) {
    365		dev_err(&pdev->dev, "unable to allocate device\n");
    366		goto err_reg;
    367	}
    368
    369	pht->caddr = pci_iomap(pdev, 0, 0);
    370	if (pht->caddr == NULL) {
    371		dev_err(&pdev->dev, "can't remap conf space\n");
    372		goto err_fr;
    373	}
    374	pht->iaddr = pci_iomap(pdev, 2, 0);
    375	if (pht->iaddr == NULL) {
    376		dev_err(&pdev->dev, "can't remap input space\n");
    377		goto err_unmc;
    378	}
    379	pht->oaddr = pci_iomap(pdev, 3, 0);
    380	if (pht->oaddr == NULL) {
    381		dev_err(&pdev->dev, "can't remap output space\n");
    382		goto err_unmi;
    383	}
    384
    385	mutex_init(&pht->open_lock);
    386	spin_lock_init(&pht->regs_lock);
    387	init_waitqueue_head(&pht->wait);
    388	cdev_init(&pht->cdev, &phantom_file_ops);
    389	pht->cdev.owner = THIS_MODULE;
    390
    391	iowrite32(0, pht->caddr + PHN_IRQCTL);
    392	ioread32(pht->caddr + PHN_IRQCTL); /* PCI posting */
    393	retval = request_irq(pdev->irq, phantom_isr,
    394			IRQF_SHARED, "phantom", pht);
    395	if (retval) {
    396		dev_err(&pdev->dev, "can't establish ISR\n");
    397		goto err_unmo;
    398	}
    399
    400	retval = cdev_add(&pht->cdev, MKDEV(phantom_major, minor), 1);
    401	if (retval) {
    402		dev_err(&pdev->dev, "chardev registration failed\n");
    403		goto err_irq;
    404	}
    405
    406	if (IS_ERR(device_create(phantom_class, &pdev->dev,
    407				 MKDEV(phantom_major, minor), NULL,
    408				 "phantom%u", minor)))
    409		dev_err(&pdev->dev, "can't create device\n");
    410
    411	pci_set_drvdata(pdev, pht);
    412
    413	return 0;
    414err_irq:
    415	free_irq(pdev->irq, pht);
    416err_unmo:
    417	pci_iounmap(pdev, pht->oaddr);
    418err_unmi:
    419	pci_iounmap(pdev, pht->iaddr);
    420err_unmc:
    421	pci_iounmap(pdev, pht->caddr);
    422err_fr:
    423	kfree(pht);
    424err_reg:
    425	pci_release_regions(pdev);
    426err_null:
    427	phantom_devices[minor] = 0;
    428err_dis:
    429	pci_disable_device(pdev);
    430err:
    431	return retval;
    432}
    433
    434static void phantom_remove(struct pci_dev *pdev)
    435{
    436	struct phantom_device *pht = pci_get_drvdata(pdev);
    437	unsigned int minor = MINOR(pht->cdev.dev);
    438
    439	device_destroy(phantom_class, MKDEV(phantom_major, minor));
    440
    441	cdev_del(&pht->cdev);
    442
    443	iowrite32(0, pht->caddr + PHN_IRQCTL);
    444	ioread32(pht->caddr + PHN_IRQCTL); /* PCI posting */
    445	free_irq(pdev->irq, pht);
    446
    447	pci_iounmap(pdev, pht->oaddr);
    448	pci_iounmap(pdev, pht->iaddr);
    449	pci_iounmap(pdev, pht->caddr);
    450
    451	kfree(pht);
    452
    453	pci_release_regions(pdev);
    454
    455	phantom_devices[minor] = 0;
    456
    457	pci_disable_device(pdev);
    458}
    459
    460static int __maybe_unused phantom_suspend(struct device *dev_d)
    461{
    462	struct phantom_device *dev = dev_get_drvdata(dev_d);
    463
    464	iowrite32(0, dev->caddr + PHN_IRQCTL);
    465	ioread32(dev->caddr + PHN_IRQCTL); /* PCI posting */
    466
    467	synchronize_irq(to_pci_dev(dev_d)->irq);
    468
    469	return 0;
    470}
    471
    472static int __maybe_unused phantom_resume(struct device *dev_d)
    473{
    474	struct phantom_device *dev = dev_get_drvdata(dev_d);
    475
    476	iowrite32(0, dev->caddr + PHN_IRQCTL);
    477
    478	return 0;
    479}
    480
    481static struct pci_device_id phantom_pci_tbl[] = {
    482	{ .vendor = PCI_VENDOR_ID_PLX, .device = PCI_DEVICE_ID_PLX_9050,
    483	  .subvendor = PCI_VENDOR_ID_PLX, .subdevice = PCI_DEVICE_ID_PLX_9050,
    484	  .class = PCI_CLASS_BRIDGE_OTHER << 8, .class_mask = 0xffff00 },
    485	{ 0, }
    486};
    487MODULE_DEVICE_TABLE(pci, phantom_pci_tbl);
    488
    489static SIMPLE_DEV_PM_OPS(phantom_pm_ops, phantom_suspend, phantom_resume);
    490
    491static struct pci_driver phantom_pci_driver = {
    492	.name = "phantom",
    493	.id_table = phantom_pci_tbl,
    494	.probe = phantom_probe,
    495	.remove = phantom_remove,
    496	.driver.pm = &phantom_pm_ops,
    497};
    498
    499static CLASS_ATTR_STRING(version, 0444, PHANTOM_VERSION);
    500
    501static int __init phantom_init(void)
    502{
    503	int retval;
    504	dev_t dev;
    505
    506	phantom_class = class_create(THIS_MODULE, "phantom");
    507	if (IS_ERR(phantom_class)) {
    508		retval = PTR_ERR(phantom_class);
    509		printk(KERN_ERR "phantom: can't register phantom class\n");
    510		goto err;
    511	}
    512	retval = class_create_file(phantom_class, &class_attr_version.attr);
    513	if (retval) {
    514		printk(KERN_ERR "phantom: can't create sysfs version file\n");
    515		goto err_class;
    516	}
    517
    518	retval = alloc_chrdev_region(&dev, 0, PHANTOM_MAX_MINORS, "phantom");
    519	if (retval) {
    520		printk(KERN_ERR "phantom: can't register character device\n");
    521		goto err_attr;
    522	}
    523	phantom_major = MAJOR(dev);
    524
    525	retval = pci_register_driver(&phantom_pci_driver);
    526	if (retval) {
    527		printk(KERN_ERR "phantom: can't register pci driver\n");
    528		goto err_unchr;
    529	}
    530
    531	printk(KERN_INFO "Phantom Linux Driver, version " PHANTOM_VERSION ", "
    532			"init OK\n");
    533
    534	return 0;
    535err_unchr:
    536	unregister_chrdev_region(dev, PHANTOM_MAX_MINORS);
    537err_attr:
    538	class_remove_file(phantom_class, &class_attr_version.attr);
    539err_class:
    540	class_destroy(phantom_class);
    541err:
    542	return retval;
    543}
    544
    545static void __exit phantom_exit(void)
    546{
    547	pci_unregister_driver(&phantom_pci_driver);
    548
    549	unregister_chrdev_region(MKDEV(phantom_major, 0), PHANTOM_MAX_MINORS);
    550
    551	class_remove_file(phantom_class, &class_attr_version.attr);
    552	class_destroy(phantom_class);
    553
    554	pr_debug("phantom: module successfully removed\n");
    555}
    556
    557module_init(phantom_init);
    558module_exit(phantom_exit);
    559
    560MODULE_AUTHOR("Jiri Slaby <jirislaby@gmail.com>");
    561MODULE_DESCRIPTION("Sensable Phantom driver (PCI devices)");
    562MODULE_LICENSE("GPL");
    563MODULE_VERSION(PHANTOM_VERSION);