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

syscall.c (2750B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * For architectures where we want to allow direct access to the PCI config
      4 * stuff - it would probably be preferable on PCs too, but there people
      5 * just do it by hand with the magic northbridge registers.
      6 */
      7
      8#include <linux/errno.h>
      9#include <linux/pci.h>
     10#include <linux/security.h>
     11#include <linux/syscalls.h>
     12#include <linux/uaccess.h>
     13#include "pci.h"
     14
     15SYSCALL_DEFINE5(pciconfig_read, unsigned long, bus, unsigned long, dfn,
     16		unsigned long, off, unsigned long, len, void __user *, buf)
     17{
     18	struct pci_dev *dev;
     19	u8 byte;
     20	u16 word;
     21	u32 dword;
     22	int err, cfg_ret;
     23
     24	err = -EPERM;
     25	dev = NULL;
     26	if (!capable(CAP_SYS_ADMIN))
     27		goto error;
     28
     29	err = -ENODEV;
     30	dev = pci_get_domain_bus_and_slot(0, bus, dfn);
     31	if (!dev)
     32		goto error;
     33
     34	switch (len) {
     35	case 1:
     36		cfg_ret = pci_user_read_config_byte(dev, off, &byte);
     37		break;
     38	case 2:
     39		cfg_ret = pci_user_read_config_word(dev, off, &word);
     40		break;
     41	case 4:
     42		cfg_ret = pci_user_read_config_dword(dev, off, &dword);
     43		break;
     44	default:
     45		err = -EINVAL;
     46		goto error;
     47	}
     48
     49	err = -EIO;
     50	if (cfg_ret)
     51		goto error;
     52
     53	switch (len) {
     54	case 1:
     55		err = put_user(byte, (unsigned char __user *)buf);
     56		break;
     57	case 2:
     58		err = put_user(word, (unsigned short __user *)buf);
     59		break;
     60	case 4:
     61		err = put_user(dword, (unsigned int __user *)buf);
     62		break;
     63	}
     64	pci_dev_put(dev);
     65	return err;
     66
     67error:
     68	/* ??? XFree86 doesn't even check the return value.  They
     69	   just look for 0xffffffff in the output, since that's what
     70	   they get instead of a machine check on x86.  */
     71	switch (len) {
     72	case 1:
     73		put_user(-1, (unsigned char __user *)buf);
     74		break;
     75	case 2:
     76		put_user(-1, (unsigned short __user *)buf);
     77		break;
     78	case 4:
     79		put_user(-1, (unsigned int __user *)buf);
     80		break;
     81	}
     82	pci_dev_put(dev);
     83	return err;
     84}
     85
     86SYSCALL_DEFINE5(pciconfig_write, unsigned long, bus, unsigned long, dfn,
     87		unsigned long, off, unsigned long, len, void __user *, buf)
     88{
     89	struct pci_dev *dev;
     90	u8 byte;
     91	u16 word;
     92	u32 dword;
     93	int err = 0;
     94
     95	if (!capable(CAP_SYS_ADMIN) ||
     96	    security_locked_down(LOCKDOWN_PCI_ACCESS))
     97		return -EPERM;
     98
     99	dev = pci_get_domain_bus_and_slot(0, bus, dfn);
    100	if (!dev)
    101		return -ENODEV;
    102
    103	switch (len) {
    104	case 1:
    105		err = get_user(byte, (u8 __user *)buf);
    106		if (err)
    107			break;
    108		err = pci_user_write_config_byte(dev, off, byte);
    109		if (err)
    110			err = -EIO;
    111		break;
    112
    113	case 2:
    114		err = get_user(word, (u16 __user *)buf);
    115		if (err)
    116			break;
    117		err = pci_user_write_config_word(dev, off, word);
    118		if (err)
    119			err = -EIO;
    120		break;
    121
    122	case 4:
    123		err = get_user(dword, (u32 __user *)buf);
    124		if (err)
    125			break;
    126		err = pci_user_write_config_dword(dev, off, dword);
    127		if (err)
    128			err = -EIO;
    129		break;
    130
    131	default:
    132		err = -EINVAL;
    133		break;
    134	}
    135	pci_dev_put(dev);
    136	return err;
    137}