Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * For architectures where we want to allow direct access to the PCI config
0004  * stuff - it would probably be preferable on PCs too, but there people
0005  * just do it by hand with the magic northbridge registers.
0006  */
0007 
0008 #include <linux/errno.h>
0009 #include <linux/pci.h>
0010 #include <linux/security.h>
0011 #include <linux/syscalls.h>
0012 #include <linux/uaccess.h>
0013 #include "pci.h"
0014 
0015 SYSCALL_DEFINE5(pciconfig_read, unsigned long, bus, unsigned long, dfn,
0016         unsigned long, off, unsigned long, len, void __user *, buf)
0017 {
0018     struct pci_dev *dev;
0019     u8 byte;
0020     u16 word;
0021     u32 dword;
0022     int err, cfg_ret;
0023 
0024     err = -EPERM;
0025     dev = NULL;
0026     if (!capable(CAP_SYS_ADMIN))
0027         goto error;
0028 
0029     err = -ENODEV;
0030     dev = pci_get_domain_bus_and_slot(0, bus, dfn);
0031     if (!dev)
0032         goto error;
0033 
0034     switch (len) {
0035     case 1:
0036         cfg_ret = pci_user_read_config_byte(dev, off, &byte);
0037         break;
0038     case 2:
0039         cfg_ret = pci_user_read_config_word(dev, off, &word);
0040         break;
0041     case 4:
0042         cfg_ret = pci_user_read_config_dword(dev, off, &dword);
0043         break;
0044     default:
0045         err = -EINVAL;
0046         goto error;
0047     }
0048 
0049     err = -EIO;
0050     if (cfg_ret)
0051         goto error;
0052 
0053     switch (len) {
0054     case 1:
0055         err = put_user(byte, (unsigned char __user *)buf);
0056         break;
0057     case 2:
0058         err = put_user(word, (unsigned short __user *)buf);
0059         break;
0060     case 4:
0061         err = put_user(dword, (unsigned int __user *)buf);
0062         break;
0063     }
0064     pci_dev_put(dev);
0065     return err;
0066 
0067 error:
0068     /* ??? XFree86 doesn't even check the return value.  They
0069        just look for 0xffffffff in the output, since that's what
0070        they get instead of a machine check on x86.  */
0071     switch (len) {
0072     case 1:
0073         put_user(-1, (unsigned char __user *)buf);
0074         break;
0075     case 2:
0076         put_user(-1, (unsigned short __user *)buf);
0077         break;
0078     case 4:
0079         put_user(-1, (unsigned int __user *)buf);
0080         break;
0081     }
0082     pci_dev_put(dev);
0083     return err;
0084 }
0085 
0086 SYSCALL_DEFINE5(pciconfig_write, unsigned long, bus, unsigned long, dfn,
0087         unsigned long, off, unsigned long, len, void __user *, buf)
0088 {
0089     struct pci_dev *dev;
0090     u8 byte;
0091     u16 word;
0092     u32 dword;
0093     int err = 0;
0094 
0095     if (!capable(CAP_SYS_ADMIN) ||
0096         security_locked_down(LOCKDOWN_PCI_ACCESS))
0097         return -EPERM;
0098 
0099     dev = pci_get_domain_bus_and_slot(0, bus, dfn);
0100     if (!dev)
0101         return -ENODEV;
0102 
0103     switch (len) {
0104     case 1:
0105         err = get_user(byte, (u8 __user *)buf);
0106         if (err)
0107             break;
0108         err = pci_user_write_config_byte(dev, off, byte);
0109         if (err)
0110             err = -EIO;
0111         break;
0112 
0113     case 2:
0114         err = get_user(word, (u16 __user *)buf);
0115         if (err)
0116             break;
0117         err = pci_user_write_config_word(dev, off, word);
0118         if (err)
0119             err = -EIO;
0120         break;
0121 
0122     case 4:
0123         err = get_user(dword, (u32 __user *)buf);
0124         if (err)
0125             break;
0126         err = pci_user_write_config_dword(dev, off, dword);
0127         if (err)
0128             err = -EIO;
0129         break;
0130 
0131     default:
0132         err = -EINVAL;
0133         break;
0134     }
0135     pci_dev_put(dev);
0136     return err;
0137 }