Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 91219bcb authored by Jaswinder Singh Rajput's avatar Jaswinder Singh Rajput Committed by Ingo Molnar
Browse files

x86: cpu_debug add write support for MSRs



Supported write flag for registers.
currently write is enabled only for PMC MSR.

[root@ht]# cat /sys/kernel/debug/x86/cpu/cpu1/pmc/0x300/value
0x0

[root@ht]# echo 1234 > /sys/kernel/debug/x86/cpu/cpu1/pmc/0x300/value
[root@ht]# cat /sys/kernel/debug/x86/cpu/cpu1/pmc/0x300/value
0x4d2

[root@ht]# echo 0x1234 > /sys/kernel/debug/x86/cpu/cpu1/pmc/0x300/value
[root@ht]# cat /sys/kernel/debug/x86/cpu/cpu1/pmc/0x300/value
0x1234

Signed-off-by: default avatarJaswinder Singh Rajput <jaswinderrajput@gmail.com>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent 02dde8b4
Loading
Loading
Loading
Loading
+11 −5
Original line number Diff line number Diff line
@@ -171,16 +171,22 @@ struct cpu_private {
struct cpu_debug_base {
	char			*name;		/* Register name	*/
	unsigned		flag;		/* Register flag	*/
	unsigned		write;		/* Register write flag	*/
};

struct cpu_cpuX_base {
	struct dentry		*dentry;	/* Register dentry	*/
	int			init;		/* Register index file	*/
};

/*
 * Currently it looks similar to cpu_debug_base but once we add more files
 * cpu_file_base will go in different direction
 */
struct cpu_file_base {
	char			*name;		/* Register file name	*/
	unsigned		flag;		/* Register file flag	*/
	unsigned		write;		/* Register write flag	*/
};

struct cpu_cpuX_base {
	struct dentry		*dentry;	/* Register dentry	*/
	int			init;		/* Register index file	*/
};

struct cpu_debug_range {
+86 −32
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@
#include <linux/seq_file.h>
#include <linux/debugfs.h>
#include <linux/kprobes.h>
#include <linux/uaccess.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/percpu.h>
@@ -40,41 +41,41 @@ static DEFINE_MUTEX(cpu_debug_lock);
static struct dentry *cpu_debugfs_dir;

static struct cpu_debug_base cpu_base[] = {
	{ "mc",		CPU_MC		},	/* Machine Check	*/
	{ "monitor",	CPU_MONITOR	},	/* Monitor		*/
	{ "time",	CPU_TIME	},	/* Time			*/
	{ "pmc",	CPU_PMC		},	/* Performance Monitor	*/
	{ "platform",	CPU_PLATFORM	},	/* Platform		*/
	{ "apic",	CPU_APIC	},	/* APIC			*/
	{ "poweron",	CPU_POWERON	},	/* Power-on		*/
	{ "control",	CPU_CONTROL	},	/* Control		*/
	{ "features",	CPU_FEATURES	},	/* Features control	*/
	{ "lastbranch",	CPU_LBRANCH	},	/* Last Branch		*/
	{ "bios",	CPU_BIOS	},	/* BIOS			*/
	{ "freq",	CPU_FREQ	},	/* Frequency		*/
	{ "mtrr",	CPU_MTRR	},	/* MTRR			*/
	{ "perf",	CPU_PERF	},	/* Performance		*/
	{ "cache",	CPU_CACHE	},	/* Cache		*/
	{ "sysenter",	CPU_SYSENTER	},	/* Sysenter		*/
	{ "therm",	CPU_THERM	},	/* Thermal		*/
	{ "misc",	CPU_MISC	},	/* Miscellaneous	*/
	{ "debug",	CPU_DEBUG	},	/* Debug		*/
	{ "pat",	CPU_PAT		},	/* PAT			*/
	{ "vmx",	CPU_VMX		},	/* VMX			*/
	{ "call",	CPU_CALL	},	/* System Call		*/
	{ "base",	CPU_BASE	},	/* BASE Address		*/
	{ "smm",	CPU_SMM		},	/* System mgmt mode	*/
	{ "svm",	CPU_SVM		},	/*Secure Virtial Machine*/
	{ "osvm",	CPU_OSVM	},	/* OS-Visible Workaround*/
	{ "tss",	CPU_TSS		},	/* Task Stack Segment	*/
	{ "cr",		CPU_CR		},	/* Control Registers	*/
	{ "dt",		CPU_DT		},	/* Descriptor Table	*/
	{ "registers",	CPU_REG_ALL	},	/* Select all Registers	*/
	{ "mc",		CPU_MC,		0	},
	{ "monitor",	CPU_MONITOR,	0	},
	{ "time",	CPU_TIME,	0	},
	{ "pmc",	CPU_PMC,	1	},
	{ "platform",	CPU_PLATFORM,	0	},
	{ "apic",	CPU_APIC,	0	},
	{ "poweron",	CPU_POWERON,	0	},
	{ "control",	CPU_CONTROL,	0	},
	{ "features",	CPU_FEATURES,	0	},
	{ "lastbranch",	CPU_LBRANCH,	0	},
	{ "bios",	CPU_BIOS,	0	},
	{ "freq",	CPU_FREQ,	0	},
	{ "mtrr",	CPU_MTRR,	0	},
	{ "perf",	CPU_PERF,	0	},
	{ "cache",	CPU_CACHE,	0	},
	{ "sysenter",	CPU_SYSENTER,	0	},
	{ "therm",	CPU_THERM,	0	},
	{ "misc",	CPU_MISC,	0	},
	{ "debug",	CPU_DEBUG,	0	},
	{ "pat",	CPU_PAT,	0	},
	{ "vmx",	CPU_VMX,	0	},
	{ "call",	CPU_CALL,	0	},
	{ "base",	CPU_BASE,	0	},
	{ "smm",	CPU_SMM,	0	},
	{ "svm",	CPU_SVM,	0	},
	{ "osvm",	CPU_OSVM,	0	},
	{ "tss",	CPU_TSS,	0	},
	{ "cr",		CPU_CR,		0	},
	{ "dt",		CPU_DT,		0	},
	{ "registers",	CPU_REG_ALL,	0	},
};

static struct cpu_file_base cpu_file[] = {
	{ "index",	CPU_REG_ALL	},	/* index		*/
	{ "value",	CPU_REG_ALL	},	/* value		*/
	{ "index",	CPU_REG_ALL,	0	},
	{ "value",	CPU_REG_ALL,	1	},
};

/* Intel Registers Range */
@@ -608,9 +609,62 @@ static int cpu_seq_open(struct inode *inode, struct file *file)
	return err;
}

static int write_msr(struct cpu_private *priv, u64 val)
{
	u32 low, high;

	high = (val >> 32) & 0xffffffff;
	low = val & 0xffffffff;

	if (!wrmsr_safe_on_cpu(priv->cpu, priv->reg, low, high))
		return 0;

	return -EPERM;
}

static int write_cpu_register(struct cpu_private *priv, const char *buf)
{
	int ret = -EPERM;
	u64 val;

	ret = strict_strtoull(buf, 0, &val);
	if (ret < 0)
		return ret;

	/* Supporting only MSRs */
	if (priv->type < CPU_TSS_BIT)
		return write_msr(priv, val);

	return ret;
}

static ssize_t cpu_write(struct file *file, const char __user *ubuf,
			     size_t count, loff_t *off)
{
	struct seq_file *seq = file->private_data;
	struct cpu_private *priv = seq->private;
	char buf[19];

	if ((priv == NULL) || (count >= sizeof(buf)))
		return -EINVAL;

	if (copy_from_user(&buf, ubuf, count))
		return -EFAULT;

	buf[count] = 0;

	if ((cpu_base[priv->type].write) && (cpu_file[priv->file].write))
		if (!write_cpu_register(priv, buf))
			return count;

	return -EACCES;
}

static const struct file_operations cpu_fops = {
	.owner		= THIS_MODULE,
	.open		= cpu_seq_open,
	.read		= seq_read,
	.write		= cpu_write,
	.llseek		= seq_lseek,
	.release	= seq_release,
};