brintos

brintos / linux-shallow public Read only

0
0
Text · 2.6 KiB · 803acbf Raw
138 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * For architectures where we want to allow direct access to the PCI config4 * stuff - it would probably be preferable on PCs too, but there people5 * 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, (u8 __user *)buf);56		break;57	case 2:58		err = put_user(word, (u16 __user *)buf);59		break;60	case 4:61		err = put_user(dword, (u32 __user *)buf);62		break;63	}64	pci_dev_put(dev);65	return err;66 67error:68	/* ??? XFree86 doesn't even check the return value.  They69	   just look for 0xffffffff in the output, since that's what70	   they get instead of a machine check on x86.  */71	switch (len) {72	case 1:73		put_user(-1, (u8 __user *)buf);74		break;75	case 2:76		put_user(-1, (u16 __user *)buf);77		break;78	case 4:79		put_user(-1, (u32 __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}138