xref: /openbmc/linux/drivers/pci/syscall.c (revision 35267cea)
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