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