diff options
-rwxr-xr-x | arch/x86/include/asm/cpu_debug.h | 16 | ||||
-rwxr-xr-x | arch/x86/kernel/cpu/cpu_debug.c | 118 |
2 files changed, 97 insertions, 37 deletions
diff --git a/arch/x86/include/asm/cpu_debug.h b/arch/x86/include/asm/cpu_debug.h index d24d64fcee04..56f1635e4617 100755 --- a/arch/x86/include/asm/cpu_debug.h +++ b/arch/x86/include/asm/cpu_debug.h | |||
@@ -171,16 +171,22 @@ struct cpu_private { | |||
171 | struct cpu_debug_base { | 171 | struct cpu_debug_base { |
172 | char *name; /* Register name */ | 172 | char *name; /* Register name */ |
173 | unsigned flag; /* Register flag */ | 173 | unsigned flag; /* Register flag */ |
174 | unsigned write; /* Register write flag */ | ||
174 | }; | 175 | }; |
175 | 176 | ||
176 | struct cpu_cpuX_base { | 177 | /* |
177 | struct dentry *dentry; /* Register dentry */ | 178 | * Currently it looks similar to cpu_debug_base but once we add more files |
178 | int init; /* Register index file */ | 179 | * cpu_file_base will go in different direction |
179 | }; | 180 | */ |
180 | |||
181 | struct cpu_file_base { | 181 | struct cpu_file_base { |
182 | char *name; /* Register file name */ | 182 | char *name; /* Register file name */ |
183 | unsigned flag; /* Register file flag */ | 183 | unsigned flag; /* Register file flag */ |
184 | unsigned write; /* Register write flag */ | ||
185 | }; | ||
186 | |||
187 | struct cpu_cpuX_base { | ||
188 | struct dentry *dentry; /* Register dentry */ | ||
189 | int init; /* Register index file */ | ||
184 | }; | 190 | }; |
185 | 191 | ||
186 | struct cpu_debug_range { | 192 | struct cpu_debug_range { |
diff --git a/arch/x86/kernel/cpu/cpu_debug.c b/arch/x86/kernel/cpu/cpu_debug.c index 9abbcbd933cc..21c0cf8ced18 100755 --- a/arch/x86/kernel/cpu/cpu_debug.c +++ b/arch/x86/kernel/cpu/cpu_debug.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <linux/seq_file.h> | 11 | #include <linux/seq_file.h> |
12 | #include <linux/debugfs.h> | 12 | #include <linux/debugfs.h> |
13 | #include <linux/kprobes.h> | 13 | #include <linux/kprobes.h> |
14 | #include <linux/uaccess.h> | ||
14 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
15 | #include <linux/module.h> | 16 | #include <linux/module.h> |
16 | #include <linux/percpu.h> | 17 | #include <linux/percpu.h> |
@@ -40,41 +41,41 @@ static DEFINE_MUTEX(cpu_debug_lock); | |||
40 | static struct dentry *cpu_debugfs_dir; | 41 | static struct dentry *cpu_debugfs_dir; |
41 | 42 | ||
42 | static struct cpu_debug_base cpu_base[] = { | 43 | static struct cpu_debug_base cpu_base[] = { |
43 | { "mc", CPU_MC }, /* Machine Check */ | 44 | { "mc", CPU_MC, 0 }, |
44 | { "monitor", CPU_MONITOR }, /* Monitor */ | 45 | { "monitor", CPU_MONITOR, 0 }, |
45 | { "time", CPU_TIME }, /* Time */ | 46 | { "time", CPU_TIME, 0 }, |
46 | { "pmc", CPU_PMC }, /* Performance Monitor */ | 47 | { "pmc", CPU_PMC, 1 }, |
47 | { "platform", CPU_PLATFORM }, /* Platform */ | 48 | { "platform", CPU_PLATFORM, 0 }, |
48 | { "apic", CPU_APIC }, /* APIC */ | 49 | { "apic", CPU_APIC, 0 }, |
49 | { "poweron", CPU_POWERON }, /* Power-on */ | 50 | { "poweron", CPU_POWERON, 0 }, |
50 | { "control", CPU_CONTROL }, /* Control */ | 51 | { "control", CPU_CONTROL, 0 }, |
51 | { "features", CPU_FEATURES }, /* Features control */ | 52 | { "features", CPU_FEATURES, 0 }, |
52 | { "lastbranch", CPU_LBRANCH }, /* Last Branch */ | 53 | { "lastbranch", CPU_LBRANCH, 0 }, |
53 | { "bios", CPU_BIOS }, /* BIOS */ | 54 | { "bios", CPU_BIOS, 0 }, |
54 | { "freq", CPU_FREQ }, /* Frequency */ | 55 | { "freq", CPU_FREQ, 0 }, |
55 | { "mtrr", CPU_MTRR }, /* MTRR */ | 56 | { "mtrr", CPU_MTRR, 0 }, |
56 | { "perf", CPU_PERF }, /* Performance */ | 57 | { "perf", CPU_PERF, 0 }, |
57 | { "cache", CPU_CACHE }, /* Cache */ | 58 | { "cache", CPU_CACHE, 0 }, |
58 | { "sysenter", CPU_SYSENTER }, /* Sysenter */ | 59 | { "sysenter", CPU_SYSENTER, 0 }, |
59 | { "therm", CPU_THERM }, /* Thermal */ | 60 | { "therm", CPU_THERM, 0 }, |
60 | { "misc", CPU_MISC }, /* Miscellaneous */ | 61 | { "misc", CPU_MISC, 0 }, |
61 | { "debug", CPU_DEBUG }, /* Debug */ | 62 | { "debug", CPU_DEBUG, 0 }, |
62 | { "pat", CPU_PAT }, /* PAT */ | 63 | { "pat", CPU_PAT, 0 }, |
63 | { "vmx", CPU_VMX }, /* VMX */ | 64 | { "vmx", CPU_VMX, 0 }, |
64 | { "call", CPU_CALL }, /* System Call */ | 65 | { "call", CPU_CALL, 0 }, |
65 | { "base", CPU_BASE }, /* BASE Address */ | 66 | { "base", CPU_BASE, 0 }, |
66 | { "smm", CPU_SMM }, /* System mgmt mode */ | 67 | { "smm", CPU_SMM, 0 }, |
67 | { "svm", CPU_SVM }, /*Secure Virtial Machine*/ | 68 | { "svm", CPU_SVM, 0 }, |
68 | { "osvm", CPU_OSVM }, /* OS-Visible Workaround*/ | 69 | { "osvm", CPU_OSVM, 0 }, |
69 | { "tss", CPU_TSS }, /* Task Stack Segment */ | 70 | { "tss", CPU_TSS, 0 }, |
70 | { "cr", CPU_CR }, /* Control Registers */ | 71 | { "cr", CPU_CR, 0 }, |
71 | { "dt", CPU_DT }, /* Descriptor Table */ | 72 | { "dt", CPU_DT, 0 }, |
72 | { "registers", CPU_REG_ALL }, /* Select all Registers */ | 73 | { "registers", CPU_REG_ALL, 0 }, |
73 | }; | 74 | }; |
74 | 75 | ||
75 | static struct cpu_file_base cpu_file[] = { | 76 | static struct cpu_file_base cpu_file[] = { |
76 | { "index", CPU_REG_ALL }, /* index */ | 77 | { "index", CPU_REG_ALL, 0 }, |
77 | { "value", CPU_REG_ALL }, /* value */ | 78 | { "value", CPU_REG_ALL, 1 }, |
78 | }; | 79 | }; |
79 | 80 | ||
80 | /* Intel Registers Range */ | 81 | /* Intel Registers Range */ |
@@ -608,9 +609,62 @@ static int cpu_seq_open(struct inode *inode, struct file *file) | |||
608 | return err; | 609 | return err; |
609 | } | 610 | } |
610 | 611 | ||
612 | static int write_msr(struct cpu_private *priv, u64 val) | ||
613 | { | ||
614 | u32 low, high; | ||
615 | |||
616 | high = (val >> 32) & 0xffffffff; | ||
617 | low = val & 0xffffffff; | ||
618 | |||
619 | if (!wrmsr_safe_on_cpu(priv->cpu, priv->reg, low, high)) | ||
620 | return 0; | ||
621 | |||
622 | return -EPERM; | ||
623 | } | ||
624 | |||
625 | static int write_cpu_register(struct cpu_private *priv, const char *buf) | ||
626 | { | ||
627 | int ret = -EPERM; | ||
628 | u64 val; | ||
629 | |||
630 | ret = strict_strtoull(buf, 0, &val); | ||
631 | if (ret < 0) | ||
632 | return ret; | ||
633 | |||
634 | /* Supporting only MSRs */ | ||
635 | if (priv->type < CPU_TSS_BIT) | ||
636 | return write_msr(priv, val); | ||
637 | |||
638 | return ret; | ||
639 | } | ||
640 | |||
641 | static ssize_t cpu_write(struct file *file, const char __user *ubuf, | ||
642 | size_t count, loff_t *off) | ||
643 | { | ||
644 | struct seq_file *seq = file->private_data; | ||
645 | struct cpu_private *priv = seq->private; | ||
646 | char buf[19]; | ||
647 | |||
648 | if ((priv == NULL) || (count >= sizeof(buf))) | ||
649 | return -EINVAL; | ||
650 | |||
651 | if (copy_from_user(&buf, ubuf, count)) | ||
652 | return -EFAULT; | ||
653 | |||
654 | buf[count] = 0; | ||
655 | |||
656 | if ((cpu_base[priv->type].write) && (cpu_file[priv->file].write)) | ||
657 | if (!write_cpu_register(priv, buf)) | ||
658 | return count; | ||
659 | |||
660 | return -EACCES; | ||
661 | } | ||
662 | |||
611 | static const struct file_operations cpu_fops = { | 663 | static const struct file_operations cpu_fops = { |
664 | .owner = THIS_MODULE, | ||
612 | .open = cpu_seq_open, | 665 | .open = cpu_seq_open, |
613 | .read = seq_read, | 666 | .read = seq_read, |
667 | .write = cpu_write, | ||
614 | .llseek = seq_lseek, | 668 | .llseek = seq_lseek, |
615 | .release = seq_release, | 669 | .release = seq_release, |
616 | }; | 670 | }; |