xref: /openbmc/linux/arch/x86/kernel/msr.c (revision 5b87c058)
1a94da204SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
29a163ed8SThomas Gleixner /* ----------------------------------------------------------------------- *
39a163ed8SThomas Gleixner  *
42b06ac86SH. Peter Anvin  *   Copyright 2000-2008 H. Peter Anvin - All Rights Reserved
5ff55df53SH. Peter Anvin  *   Copyright 2009 Intel Corporation; author: H. Peter Anvin
69a163ed8SThomas Gleixner  *
79a163ed8SThomas Gleixner  * ----------------------------------------------------------------------- */
89a163ed8SThomas Gleixner 
99a163ed8SThomas Gleixner /*
109a163ed8SThomas Gleixner  * x86 MSR access device
119a163ed8SThomas Gleixner  *
129a163ed8SThomas Gleixner  * This device is accessed by lseek() to the appropriate register number
139a163ed8SThomas Gleixner  * and then read/write in chunks of 8 bytes.  A larger size means multiple
149a163ed8SThomas Gleixner  * reads or writes of the same register.
159a163ed8SThomas Gleixner  *
169a163ed8SThomas Gleixner  * This driver uses /dev/cpu/%d/msr where %d is the minor number, and on
179a163ed8SThomas Gleixner  * an SMP box will direct the access to CPU %d.
189a163ed8SThomas Gleixner  */
199a163ed8SThomas Gleixner 
20951a18c6SFabian Frederick #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
21951a18c6SFabian Frederick 
229a163ed8SThomas Gleixner #include <linux/module.h>
239a163ed8SThomas Gleixner 
249a163ed8SThomas Gleixner #include <linux/types.h>
259a163ed8SThomas Gleixner #include <linux/errno.h>
269a163ed8SThomas Gleixner #include <linux/fcntl.h>
279a163ed8SThomas Gleixner #include <linux/init.h>
289a163ed8SThomas Gleixner #include <linux/poll.h>
299a163ed8SThomas Gleixner #include <linux/smp.h>
309a163ed8SThomas Gleixner #include <linux/major.h>
319a163ed8SThomas Gleixner #include <linux/fs.h>
329a163ed8SThomas Gleixner #include <linux/device.h>
339a163ed8SThomas Gleixner #include <linux/cpu.h>
349a163ed8SThomas Gleixner #include <linux/notifier.h>
35448dd2faSJaswinder Singh Rajput #include <linux/uaccess.h>
365a0e3ad6STejun Heo #include <linux/gfp.h>
3795f5e95fSMatthew Garrett #include <linux/security.h>
389a163ed8SThomas Gleixner 
39cd4d09ecSBorislav Petkov #include <asm/cpufeature.h>
409a163ed8SThomas Gleixner #include <asm/msr.h>
419a163ed8SThomas Gleixner 
428fba38c9SSebastian Andrzej Siewior static enum cpuhp_state cpuhp_msr_state;
439a163ed8SThomas Gleixner 
44a7e1f67eSBorislav Petkov enum allow_write_msrs {
45a7e1f67eSBorislav Petkov 	MSR_WRITES_ON,
46a7e1f67eSBorislav Petkov 	MSR_WRITES_OFF,
47a7e1f67eSBorislav Petkov 	MSR_WRITES_DEFAULT,
48a7e1f67eSBorislav Petkov };
49a7e1f67eSBorislav Petkov 
50a7e1f67eSBorislav Petkov static enum allow_write_msrs allow_writes = MSR_WRITES_DEFAULT;
51a7e1f67eSBorislav Petkov 
msr_read(struct file * file,char __user * buf,size_t count,loff_t * ppos)529a163ed8SThomas Gleixner static ssize_t msr_read(struct file *file, char __user *buf,
539a163ed8SThomas Gleixner 			size_t count, loff_t *ppos)
549a163ed8SThomas Gleixner {
559a163ed8SThomas Gleixner 	u32 __user *tmp = (u32 __user *) buf;
569a163ed8SThomas Gleixner 	u32 data[2];
579a163ed8SThomas Gleixner 	u32 reg = *ppos;
586131ffaaSAl Viro 	int cpu = iminor(file_inode(file));
5985f1cb60SH. Peter Anvin 	int err = 0;
6085f1cb60SH. Peter Anvin 	ssize_t bytes = 0;
619a163ed8SThomas Gleixner 
629a163ed8SThomas Gleixner 	if (count % 8)
639a163ed8SThomas Gleixner 		return -EINVAL;	/* Invalid chunk size */
649a163ed8SThomas Gleixner 
659a163ed8SThomas Gleixner 	for (; count; count -= 8) {
669a163ed8SThomas Gleixner 		err = rdmsr_safe_on_cpu(cpu, reg, &data[0], &data[1]);
670cc0213eSH. Peter Anvin 		if (err)
6885f1cb60SH. Peter Anvin 			break;
6985f1cb60SH. Peter Anvin 		if (copy_to_user(tmp, &data, 8)) {
7085f1cb60SH. Peter Anvin 			err = -EFAULT;
7185f1cb60SH. Peter Anvin 			break;
7285f1cb60SH. Peter Anvin 		}
739a163ed8SThomas Gleixner 		tmp += 2;
7485f1cb60SH. Peter Anvin 		bytes += 8;
759a163ed8SThomas Gleixner 	}
769a163ed8SThomas Gleixner 
7785f1cb60SH. Peter Anvin 	return bytes ? bytes : err;
789a163ed8SThomas Gleixner }
799a163ed8SThomas Gleixner 
filter_write(u32 reg)80a7e1f67eSBorislav Petkov static int filter_write(u32 reg)
81a7e1f67eSBorislav Petkov {
821f35c9c0SChris Down 	/*
831f35c9c0SChris Down 	 * MSRs writes usually happen all at once, and can easily saturate kmsg.
841f35c9c0SChris Down 	 * Only allow one message every 30 seconds.
851f35c9c0SChris Down 	 *
861f35c9c0SChris Down 	 * It's possible to be smarter here and do it (for example) per-MSR, but
871f35c9c0SChris Down 	 * it would certainly be more complex, and this is enough at least to
881f35c9c0SChris Down 	 * avoid saturating the ring buffer.
891f35c9c0SChris Down 	 */
901f35c9c0SChris Down 	static DEFINE_RATELIMIT_STATE(fw_rs, 30 * HZ, 1);
911f35c9c0SChris Down 
92a7e1f67eSBorislav Petkov 	switch (allow_writes) {
93a7e1f67eSBorislav Petkov 	case MSR_WRITES_ON:  return 0;
94a7e1f67eSBorislav Petkov 	case MSR_WRITES_OFF: return -EPERM;
95a7e1f67eSBorislav Petkov 	default: break;
96a7e1f67eSBorislav Petkov 	}
97a7e1f67eSBorislav Petkov 
981f35c9c0SChris Down 	if (!__ratelimit(&fw_rs))
991f35c9c0SChris Down 		return 0;
1001f35c9c0SChris Down 
101f77f420dSBorislav Petkov 	pr_warn("Write to unrecognized MSR 0x%x by %s (pid: %d).\n",
102c31feed8SChris Down 	        reg, current->comm, current->pid);
103f77f420dSBorislav Petkov 	pr_warn("See https://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git/about for details.\n");
104a7e1f67eSBorislav Petkov 
105a7e1f67eSBorislav Petkov 	return 0;
106a7e1f67eSBorislav Petkov }
107a7e1f67eSBorislav Petkov 
msr_write(struct file * file,const char __user * buf,size_t count,loff_t * ppos)1089a163ed8SThomas Gleixner static ssize_t msr_write(struct file *file, const char __user *buf,
1099a163ed8SThomas Gleixner 			 size_t count, loff_t *ppos)
1109a163ed8SThomas Gleixner {
1119a163ed8SThomas Gleixner 	const u32 __user *tmp = (const u32 __user *)buf;
1129a163ed8SThomas Gleixner 	u32 data[2];
1139a163ed8SThomas Gleixner 	u32 reg = *ppos;
1146131ffaaSAl Viro 	int cpu = iminor(file_inode(file));
11585f1cb60SH. Peter Anvin 	int err = 0;
11685f1cb60SH. Peter Anvin 	ssize_t bytes = 0;
1179a163ed8SThomas Gleixner 
11895f5e95fSMatthew Garrett 	err = security_locked_down(LOCKDOWN_MSR);
11995f5e95fSMatthew Garrett 	if (err)
12095f5e95fSMatthew Garrett 		return err;
12195f5e95fSMatthew Garrett 
122a7e1f67eSBorislav Petkov 	err = filter_write(reg);
123a7e1f67eSBorislav Petkov 	if (err)
124a7e1f67eSBorislav Petkov 		return err;
125a7e1f67eSBorislav Petkov 
1269a163ed8SThomas Gleixner 	if (count % 8)
1279a163ed8SThomas Gleixner 		return -EINVAL;	/* Invalid chunk size */
1289a163ed8SThomas Gleixner 
1299a163ed8SThomas Gleixner 	for (; count; count -= 8) {
13085f1cb60SH. Peter Anvin 		if (copy_from_user(&data, tmp, 8)) {
13185f1cb60SH. Peter Anvin 			err = -EFAULT;
13285f1cb60SH. Peter Anvin 			break;
13385f1cb60SH. Peter Anvin 		}
134a7e1f67eSBorislav Petkov 
135a7e1f67eSBorislav Petkov 		add_taint(TAINT_CPU_OUT_OF_SPEC, LOCKDEP_STILL_OK);
136a7e1f67eSBorislav Petkov 
1379a163ed8SThomas Gleixner 		err = wrmsr_safe_on_cpu(cpu, reg, data[0], data[1]);
1380cc0213eSH. Peter Anvin 		if (err)
13985f1cb60SH. Peter Anvin 			break;
140a7e1f67eSBorislav Petkov 
1419a163ed8SThomas Gleixner 		tmp += 2;
14285f1cb60SH. Peter Anvin 		bytes += 8;
1439a163ed8SThomas Gleixner 	}
1449a163ed8SThomas Gleixner 
14585f1cb60SH. Peter Anvin 	return bytes ? bytes : err;
1469a163ed8SThomas Gleixner }
1479a163ed8SThomas Gleixner 
msr_ioctl(struct file * file,unsigned int ioc,unsigned long arg)148ff55df53SH. Peter Anvin static long msr_ioctl(struct file *file, unsigned int ioc, unsigned long arg)
149ff55df53SH. Peter Anvin {
150ff55df53SH. Peter Anvin 	u32 __user *uregs = (u32 __user *)arg;
151ff55df53SH. Peter Anvin 	u32 regs[8];
1526131ffaaSAl Viro 	int cpu = iminor(file_inode(file));
153ff55df53SH. Peter Anvin 	int err;
154ff55df53SH. Peter Anvin 
155ff55df53SH. Peter Anvin 	switch (ioc) {
156ff55df53SH. Peter Anvin 	case X86_IOC_RDMSR_REGS:
157ff55df53SH. Peter Anvin 		if (!(file->f_mode & FMODE_READ)) {
158ff55df53SH. Peter Anvin 			err = -EBADF;
159ff55df53SH. Peter Anvin 			break;
160ff55df53SH. Peter Anvin 		}
1610e96f31eSJordan Borgner 		if (copy_from_user(&regs, uregs, sizeof(regs))) {
162ff55df53SH. Peter Anvin 			err = -EFAULT;
163ff55df53SH. Peter Anvin 			break;
164ff55df53SH. Peter Anvin 		}
165ff55df53SH. Peter Anvin 		err = rdmsr_safe_regs_on_cpu(cpu, regs);
166ff55df53SH. Peter Anvin 		if (err)
167ff55df53SH. Peter Anvin 			break;
1680e96f31eSJordan Borgner 		if (copy_to_user(uregs, &regs, sizeof(regs)))
169ff55df53SH. Peter Anvin 			err = -EFAULT;
170ff55df53SH. Peter Anvin 		break;
171ff55df53SH. Peter Anvin 
172ff55df53SH. Peter Anvin 	case X86_IOC_WRMSR_REGS:
173ff55df53SH. Peter Anvin 		if (!(file->f_mode & FMODE_WRITE)) {
174ff55df53SH. Peter Anvin 			err = -EBADF;
175ff55df53SH. Peter Anvin 			break;
176ff55df53SH. Peter Anvin 		}
1770e96f31eSJordan Borgner 		if (copy_from_user(&regs, uregs, sizeof(regs))) {
178ff55df53SH. Peter Anvin 			err = -EFAULT;
179ff55df53SH. Peter Anvin 			break;
180ff55df53SH. Peter Anvin 		}
18195f5e95fSMatthew Garrett 		err = security_locked_down(LOCKDOWN_MSR);
18295f5e95fSMatthew Garrett 		if (err)
18395f5e95fSMatthew Garrett 			break;
18402a16aa1SMisono Tomohiro 
18502a16aa1SMisono Tomohiro 		err = filter_write(regs[1]);
18602a16aa1SMisono Tomohiro 		if (err)
18702a16aa1SMisono Tomohiro 			return err;
18802a16aa1SMisono Tomohiro 
18902a16aa1SMisono Tomohiro 		add_taint(TAINT_CPU_OUT_OF_SPEC, LOCKDEP_STILL_OK);
19002a16aa1SMisono Tomohiro 
191ff55df53SH. Peter Anvin 		err = wrmsr_safe_regs_on_cpu(cpu, regs);
192ff55df53SH. Peter Anvin 		if (err)
193ff55df53SH. Peter Anvin 			break;
1940e96f31eSJordan Borgner 		if (copy_to_user(uregs, &regs, sizeof(regs)))
195ff55df53SH. Peter Anvin 			err = -EFAULT;
196ff55df53SH. Peter Anvin 		break;
197ff55df53SH. Peter Anvin 
198ff55df53SH. Peter Anvin 	default:
199ff55df53SH. Peter Anvin 		err = -ENOTTY;
200ff55df53SH. Peter Anvin 		break;
201ff55df53SH. Peter Anvin 	}
202ff55df53SH. Peter Anvin 
203ff55df53SH. Peter Anvin 	return err;
204ff55df53SH. Peter Anvin }
205ff55df53SH. Peter Anvin 
msr_open(struct inode * inode,struct file * file)2069a163ed8SThomas Gleixner static int msr_open(struct inode *inode, struct file *file)
2079a163ed8SThomas Gleixner {
2086131ffaaSAl Viro 	unsigned int cpu = iminor(file_inode(file));
209494c2ebfSH. Peter Anvin 	struct cpuinfo_x86 *c;
2109a163ed8SThomas Gleixner 
211c903f045SAlan Cox 	if (!capable(CAP_SYS_RAWIO))
212c903f045SAlan Cox 		return -EPERM;
213c903f045SAlan Cox 
214d6c30405SFrederic Weisbecker 	if (cpu >= nr_cpu_ids || !cpu_online(cpu))
215d6c30405SFrederic Weisbecker 		return -ENXIO;	/* No such CPU */
216d6c30405SFrederic Weisbecker 
2175119e92eSJonathan Corbet 	c = &cpu_data(cpu);
2189a163ed8SThomas Gleixner 	if (!cpu_has(c, X86_FEATURE_MSR))
219d6c30405SFrederic Weisbecker 		return -EIO;	/* MSR not supported */
220d6c30405SFrederic Weisbecker 
221d6c30405SFrederic Weisbecker 	return 0;
2229a163ed8SThomas Gleixner }
2239a163ed8SThomas Gleixner 
2249a163ed8SThomas Gleixner /*
2259a163ed8SThomas Gleixner  * File operations we support
2269a163ed8SThomas Gleixner  */
2279a163ed8SThomas Gleixner static const struct file_operations msr_fops = {
2289a163ed8SThomas Gleixner 	.owner = THIS_MODULE,
229b25472f9SAl Viro 	.llseek = no_seek_end_llseek,
2309a163ed8SThomas Gleixner 	.read = msr_read,
2319a163ed8SThomas Gleixner 	.write = msr_write,
2329a163ed8SThomas Gleixner 	.open = msr_open,
233ff55df53SH. Peter Anvin 	.unlocked_ioctl = msr_ioctl,
234ff55df53SH. Peter Anvin 	.compat_ioctl = msr_ioctl,
2359a163ed8SThomas Gleixner };
2369a163ed8SThomas Gleixner 
msr_devnode(const struct device * dev,umode_t * mode)237*5b87c058SIvan Orlov static char *msr_devnode(const struct device *dev, umode_t *mode)
238*5b87c058SIvan Orlov {
239*5b87c058SIvan Orlov 	return kasprintf(GFP_KERNEL, "cpu/%u/msr", MINOR(dev->devt));
240*5b87c058SIvan Orlov }
241*5b87c058SIvan Orlov 
242*5b87c058SIvan Orlov static const struct class msr_class = {
243*5b87c058SIvan Orlov 	.name		= "msr",
244*5b87c058SIvan Orlov 	.devnode	= msr_devnode,
245*5b87c058SIvan Orlov };
246*5b87c058SIvan Orlov 
msr_device_create(unsigned int cpu)2478fba38c9SSebastian Andrzej Siewior static int msr_device_create(unsigned int cpu)
2489a163ed8SThomas Gleixner {
2499a163ed8SThomas Gleixner 	struct device *dev;
2509a163ed8SThomas Gleixner 
251*5b87c058SIvan Orlov 	dev = device_create(&msr_class, NULL, MKDEV(MSR_MAJOR, cpu), NULL,
252a9b12619SGreg Kroah-Hartman 			    "msr%d", cpu);
253cba0fdbcSFabian Frederick 	return PTR_ERR_OR_ZERO(dev);
254881a841fSAkinobu Mita }
255881a841fSAkinobu Mita 
msr_device_destroy(unsigned int cpu)2568fba38c9SSebastian Andrzej Siewior static int msr_device_destroy(unsigned int cpu)
257881a841fSAkinobu Mita {
258*5b87c058SIvan Orlov 	device_destroy(&msr_class, MKDEV(MSR_MAJOR, cpu));
2598fba38c9SSebastian Andrzej Siewior 	return 0;
2609a163ed8SThomas Gleixner }
2619a163ed8SThomas Gleixner 
msr_init(void)2629a163ed8SThomas Gleixner static int __init msr_init(void)
2639a163ed8SThomas Gleixner {
2648fba38c9SSebastian Andrzej Siewior 	int err;
2659a163ed8SThomas Gleixner 
2660b962d47SH. Peter Anvin 	if (__register_chrdev(MSR_MAJOR, 0, NR_CPUS, "cpu/msr", &msr_fops)) {
267951a18c6SFabian Frederick 		pr_err("unable to get major %d for msr\n", MSR_MAJOR);
2688fba38c9SSebastian Andrzej Siewior 		return -EBUSY;
2699a163ed8SThomas Gleixner 	}
270*5b87c058SIvan Orlov 	err = class_register(&msr_class);
271*5b87c058SIvan Orlov 	if (err)
2729a163ed8SThomas Gleixner 		goto out_chrdev;
273de82a01bSSrivatsa S. Bhat 
2748fba38c9SSebastian Andrzej Siewior 	err  = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "x86/msr:online",
2758fba38c9SSebastian Andrzej Siewior 				 msr_device_create, msr_device_destroy);
2768fba38c9SSebastian Andrzej Siewior 	if (err < 0)
2779a163ed8SThomas Gleixner 		goto out_class;
2788fba38c9SSebastian Andrzej Siewior 	cpuhp_msr_state = err;
2798fba38c9SSebastian Andrzej Siewior 	return 0;
2809a163ed8SThomas Gleixner 
2819a163ed8SThomas Gleixner out_class:
282*5b87c058SIvan Orlov 	class_unregister(&msr_class);
2839a163ed8SThomas Gleixner out_chrdev:
2840b962d47SH. Peter Anvin 	__unregister_chrdev(MSR_MAJOR, 0, NR_CPUS, "cpu/msr");
2859a163ed8SThomas Gleixner 	return err;
2869a163ed8SThomas Gleixner }
2878fba38c9SSebastian Andrzej Siewior module_init(msr_init);
2889a163ed8SThomas Gleixner 
msr_exit(void)2899a163ed8SThomas Gleixner static void __exit msr_exit(void)
2909a163ed8SThomas Gleixner {
2918fba38c9SSebastian Andrzej Siewior 	cpuhp_remove_state(cpuhp_msr_state);
292*5b87c058SIvan Orlov 	class_unregister(&msr_class);
293da482474SRuss Anderson 	__unregister_chrdev(MSR_MAJOR, 0, NR_CPUS, "cpu/msr");
2949a163ed8SThomas Gleixner }
module_exit(msr_exit)2959a163ed8SThomas Gleixner module_exit(msr_exit)
2969a163ed8SThomas Gleixner 
297a7e1f67eSBorislav Petkov static int set_allow_writes(const char *val, const struct kernel_param *cp)
298a7e1f67eSBorislav Petkov {
299a7e1f67eSBorislav Petkov 	/* val is NUL-terminated, see kernfs_fop_write() */
300a7e1f67eSBorislav Petkov 	char *s = strstrip((char *)val);
301a7e1f67eSBorislav Petkov 
302a7e1f67eSBorislav Petkov 	if (!strcmp(s, "on"))
303a7e1f67eSBorislav Petkov 		allow_writes = MSR_WRITES_ON;
304a7e1f67eSBorislav Petkov 	else if (!strcmp(s, "off"))
305a7e1f67eSBorislav Petkov 		allow_writes = MSR_WRITES_OFF;
306a7e1f67eSBorislav Petkov 	else
307a7e1f67eSBorislav Petkov 		allow_writes = MSR_WRITES_DEFAULT;
308a7e1f67eSBorislav Petkov 
309a7e1f67eSBorislav Petkov 	return 0;
310a7e1f67eSBorislav Petkov }
311a7e1f67eSBorislav Petkov 
get_allow_writes(char * buf,const struct kernel_param * kp)312a7e1f67eSBorislav Petkov static int get_allow_writes(char *buf, const struct kernel_param *kp)
313a7e1f67eSBorislav Petkov {
314a7e1f67eSBorislav Petkov 	const char *res;
315a7e1f67eSBorislav Petkov 
316a7e1f67eSBorislav Petkov 	switch (allow_writes) {
317a7e1f67eSBorislav Petkov 	case MSR_WRITES_ON:  res = "on"; break;
318a7e1f67eSBorislav Petkov 	case MSR_WRITES_OFF: res = "off"; break;
319a7e1f67eSBorislav Petkov 	default: res = "default"; break;
320a7e1f67eSBorislav Petkov 	}
321a7e1f67eSBorislav Petkov 
322a7e1f67eSBorislav Petkov 	return sprintf(buf, "%s\n", res);
323a7e1f67eSBorislav Petkov }
324a7e1f67eSBorislav Petkov 
325a7e1f67eSBorislav Petkov static const struct kernel_param_ops allow_writes_ops = {
326a7e1f67eSBorislav Petkov 	.set = set_allow_writes,
327a7e1f67eSBorislav Petkov 	.get = get_allow_writes
328a7e1f67eSBorislav Petkov };
329a7e1f67eSBorislav Petkov 
330a7e1f67eSBorislav Petkov module_param_cb(allow_writes, &allow_writes_ops, NULL, 0600);
331a7e1f67eSBorislav Petkov 
3329a163ed8SThomas Gleixner MODULE_AUTHOR("H. Peter Anvin <hpa@zytor.com>");
3339a163ed8SThomas Gleixner MODULE_DESCRIPTION("x86 generic MSR driver");
3349a163ed8SThomas Gleixner MODULE_LICENSE("GPL");
335