xref: /OK3568_Linux_fs/kernel/drivers/pci/syscall.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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