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