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}