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 15 SYSCALL_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 long err; 23 int cfg_ret; 24 25 if (!capable(CAP_SYS_ADMIN)) 26 return -EPERM; 27 28 err = -ENODEV; 29 dev = pci_get_domain_bus_and_slot(0, bus, dfn); 30 if (!dev) 31 goto error; 32 33 switch (len) { 34 case 1: 35 cfg_ret = pci_user_read_config_byte(dev, off, &byte); 36 break; 37 case 2: 38 cfg_ret = pci_user_read_config_word(dev, off, &word); 39 break; 40 case 4: 41 cfg_ret = pci_user_read_config_dword(dev, off, &dword); 42 break; 43 default: 44 err = -EINVAL; 45 goto error; 46 } 47 48 err = -EIO; 49 if (cfg_ret) 50 goto error; 51 52 switch (len) { 53 case 1: 54 err = put_user(byte, (unsigned char __user *)buf); 55 break; 56 case 2: 57 err = put_user(word, (unsigned short __user *)buf); 58 break; 59 case 4: 60 err = put_user(dword, (unsigned int __user *)buf); 61 break; 62 } 63 pci_dev_put(dev); 64 return err; 65 66 error: 67 /* ??? XFree86 doesn't even check the return value. They 68 just look for 0xffffffff in the output, since that's what 69 they get instead of a machine check on x86. */ 70 switch (len) { 71 case 1: 72 put_user(-1, (unsigned char __user *)buf); 73 break; 74 case 2: 75 put_user(-1, (unsigned short __user *)buf); 76 break; 77 case 4: 78 put_user(-1, (unsigned int __user *)buf); 79 break; 80 } 81 pci_dev_put(dev); 82 return err; 83 } 84 85 SYSCALL_DEFINE5(pciconfig_write, unsigned long, bus, unsigned long, dfn, 86 unsigned long, off, unsigned long, len, void __user *, buf) 87 { 88 struct pci_dev *dev; 89 u8 byte; 90 u16 word; 91 u32 dword; 92 int err = 0; 93 94 if (!capable(CAP_SYS_ADMIN) || 95 security_locked_down(LOCKDOWN_PCI_ACCESS)) 96 return -EPERM; 97 98 dev = pci_get_domain_bus_and_slot(0, bus, dfn); 99 if (!dev) 100 return -ENODEV; 101 102 switch (len) { 103 case 1: 104 err = get_user(byte, (u8 __user *)buf); 105 if (err) 106 break; 107 err = pci_user_write_config_byte(dev, off, byte); 108 if (err) 109 err = -EIO; 110 break; 111 112 case 2: 113 err = get_user(word, (u16 __user *)buf); 114 if (err) 115 break; 116 err = pci_user_write_config_word(dev, off, word); 117 if (err) 118 err = -EIO; 119 break; 120 121 case 4: 122 err = get_user(dword, (u32 __user *)buf); 123 if (err) 124 break; 125 err = pci_user_write_config_dword(dev, off, dword); 126 if (err) 127 err = -EIO; 128 break; 129 130 default: 131 err = -EINVAL; 132 break; 133 } 134 pci_dev_put(dev); 135 return err; 136 } 137