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