diff options
Diffstat (limited to 'arch/x86/kernel/cpu/cpu_debug.c')
| -rwxr-xr-x | arch/x86/kernel/cpu/cpu_debug.c | 268 |
1 files changed, 192 insertions, 76 deletions
diff --git a/arch/x86/kernel/cpu/cpu_debug.c b/arch/x86/kernel/cpu/cpu_debug.c index 9abbcbd933c..46e29ab96c6 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,43 @@ 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 | { "ver", CPU_VER, 0 }, |
| 67 | { "svm", CPU_SVM }, /*Secure Virtial Machine*/ | 68 | { "conf", CPU_CONF, 0 }, |
| 68 | { "osvm", CPU_OSVM }, /* OS-Visible Workaround*/ | 69 | { "smm", CPU_SMM, 0 }, |
| 69 | { "tss", CPU_TSS }, /* Task Stack Segment */ | 70 | { "svm", CPU_SVM, 0 }, |
| 70 | { "cr", CPU_CR }, /* Control Registers */ | 71 | { "osvm", CPU_OSVM, 0 }, |
| 71 | { "dt", CPU_DT }, /* Descriptor Table */ | 72 | { "tss", CPU_TSS, 0 }, |
| 72 | { "registers", CPU_REG_ALL }, /* Select all Registers */ | 73 | { "cr", CPU_CR, 0 }, |
| 74 | { "dt", CPU_DT, 0 }, | ||
| 75 | { "registers", CPU_REG_ALL, 0 }, | ||
| 73 | }; | 76 | }; |
| 74 | 77 | ||
| 75 | static struct cpu_file_base cpu_file[] = { | 78 | static struct cpu_file_base cpu_file[] = { |
| 76 | { "index", CPU_REG_ALL }, /* index */ | 79 | { "index", CPU_REG_ALL, 0 }, |
| 77 | { "value", CPU_REG_ALL }, /* value */ | 80 | { "value", CPU_REG_ALL, 1 }, |
| 78 | }; | 81 | }; |
| 79 | 82 | ||
| 80 | /* Intel Registers Range */ | 83 | /* Intel Registers Range */ |
| @@ -176,54 +179,59 @@ static struct cpu_debug_range cpu_intel_range[] = { | |||
| 176 | 179 | ||
| 177 | /* AMD Registers Range */ | 180 | /* AMD Registers Range */ |
| 178 | static struct cpu_debug_range cpu_amd_range[] = { | 181 | static struct cpu_debug_range cpu_amd_range[] = { |
| 179 | { 0x00000010, 0x00000010, CPU_TIME, CPU_ALL, }, | 182 | { 0x00000000, 0x00000001, CPU_MC, CPU_K10_PLUS, }, |
| 180 | { 0x0000001B, 0x0000001B, CPU_APIC, CPU_ALL, }, | 183 | { 0x00000010, 0x00000010, CPU_TIME, CPU_K8_PLUS, }, |
| 181 | { 0x000000FE, 0x000000FE, CPU_MTRR, CPU_ALL, }, | 184 | { 0x0000001B, 0x0000001B, CPU_APIC, CPU_K8_PLUS, }, |
| 182 | 185 | { 0x0000002A, 0x0000002A, CPU_POWERON, CPU_K7_PLUS }, | |
| 183 | { 0x00000174, 0x00000176, CPU_SYSENTER, CPU_ALL, }, | 186 | { 0x0000008B, 0x0000008B, CPU_VER, CPU_K8_PLUS }, |
| 184 | { 0x00000179, 0x0000017A, CPU_MC, CPU_ALL, }, | 187 | { 0x000000FE, 0x000000FE, CPU_MTRR, CPU_K8_PLUS, }, |
| 185 | { 0x0000017B, 0x0000017B, CPU_MC, CPU_ALL, }, | 188 | |
| 186 | { 0x000001D9, 0x000001D9, CPU_DEBUG, CPU_ALL, }, | 189 | { 0x00000174, 0x00000176, CPU_SYSENTER, CPU_K8_PLUS, }, |
| 187 | { 0x000001DB, 0x000001DE, CPU_LBRANCH, CPU_ALL, }, | 190 | { 0x00000179, 0x0000017B, CPU_MC, CPU_K8_PLUS, }, |
| 188 | 191 | { 0x000001D9, 0x000001D9, CPU_DEBUG, CPU_K8_PLUS, }, | |
| 189 | { 0x00000200, 0x0000020F, CPU_MTRR, CPU_ALL, }, | 192 | { 0x000001DB, 0x000001DE, CPU_LBRANCH, CPU_K8_PLUS, }, |
| 190 | { 0x00000250, 0x00000250, CPU_MTRR, CPU_ALL, }, | 193 | |
| 191 | { 0x00000258, 0x00000259, CPU_MTRR, CPU_ALL, }, | 194 | { 0x00000200, 0x0000020F, CPU_MTRR, CPU_K8_PLUS, }, |
| 192 | { 0x00000268, 0x0000026F, CPU_MTRR, CPU_ALL, }, | 195 | { 0x00000250, 0x00000250, CPU_MTRR, CPU_K8_PLUS, }, |
| 193 | { 0x00000277, 0x00000277, CPU_PAT, CPU_ALL, }, | 196 | { 0x00000258, 0x00000259, CPU_MTRR, CPU_K8_PLUS, }, |
| 194 | { 0x000002FF, 0x000002FF, CPU_MTRR, CPU_ALL, }, | 197 | { 0x00000268, 0x0000026F, CPU_MTRR, CPU_K8_PLUS, }, |
| 195 | 198 | { 0x00000277, 0x00000277, CPU_PAT, CPU_K8_PLUS, }, | |
| 196 | { 0x00000400, 0x00000417, CPU_MC, CPU_ALL, }, | 199 | { 0x000002FF, 0x000002FF, CPU_MTRR, CPU_K8_PLUS, }, |
| 197 | 200 | ||
| 198 | { 0xC0000080, 0xC0000080, CPU_FEATURES, CPU_ALL, }, | 201 | { 0x00000400, 0x00000413, CPU_MC, CPU_K8_PLUS, }, |
| 199 | { 0xC0000081, 0xC0000084, CPU_CALL, CPU_ALL, }, | 202 | |
| 200 | { 0xC0000100, 0xC0000102, CPU_BASE, CPU_ALL, }, | 203 | { 0xC0000080, 0xC0000080, CPU_FEATURES, CPU_AMD_ALL, }, |
| 201 | { 0xC0000103, 0xC0000103, CPU_TIME, CPU_ALL, }, | 204 | { 0xC0000081, 0xC0000084, CPU_CALL, CPU_K8_PLUS, }, |
| 202 | 205 | { 0xC0000100, 0xC0000102, CPU_BASE, CPU_K8_PLUS, }, | |
| 203 | { 0xC0000408, 0xC000040A, CPU_MC, CPU_ALL, }, | 206 | { 0xC0000103, 0xC0000103, CPU_TIME, CPU_K10_PLUS, }, |
| 204 | 207 | ||
| 205 | { 0xc0010000, 0xc0010007, CPU_PMC, CPU_ALL, }, | 208 | { 0xC0010000, 0xC0010007, CPU_PMC, CPU_K8_PLUS, }, |
| 206 | { 0xc0010010, 0xc0010010, CPU_MTRR, CPU_ALL, }, | 209 | { 0xC0010010, 0xC0010010, CPU_CONF, CPU_K7_PLUS, }, |
| 207 | { 0xc0010016, 0xc001001A, CPU_MTRR, CPU_ALL, }, | 210 | { 0xC0010015, 0xC0010015, CPU_CONF, CPU_K7_PLUS, }, |
| 208 | { 0xc001001D, 0xc001001D, CPU_MTRR, CPU_ALL, }, | 211 | { 0xC0010016, 0xC001001A, CPU_MTRR, CPU_K8_PLUS, }, |
| 209 | { 0xc0010030, 0xc0010035, CPU_BIOS, CPU_ALL, }, | 212 | { 0xC001001D, 0xC001001D, CPU_MTRR, CPU_K8_PLUS, }, |
| 210 | { 0xc0010056, 0xc0010056, CPU_SMM, CPU_ALL, }, | 213 | { 0xC001001F, 0xC001001F, CPU_CONF, CPU_K8_PLUS, }, |
| 211 | { 0xc0010061, 0xc0010063, CPU_SMM, CPU_ALL, }, | 214 | { 0xC0010030, 0xC0010035, CPU_BIOS, CPU_K8_PLUS, }, |
| 212 | { 0xc0010074, 0xc0010074, CPU_MC, CPU_ALL, }, | 215 | { 0xC0010044, 0xC0010048, CPU_MC, CPU_K8_PLUS, }, |
| 213 | { 0xc0010111, 0xc0010113, CPU_SMM, CPU_ALL, }, | 216 | { 0xC0010050, 0xC0010056, CPU_SMM, CPU_K0F_PLUS, }, |
| 214 | { 0xc0010114, 0xc0010118, CPU_SVM, CPU_ALL, }, | 217 | { 0xC0010058, 0xC0010058, CPU_CONF, CPU_K10_PLUS, }, |
| 215 | { 0xc0010119, 0xc001011A, CPU_SMM, CPU_ALL, }, | 218 | { 0xC0010060, 0xC0010060, CPU_CACHE, CPU_AMD_11, }, |
| 216 | { 0xc0010140, 0xc0010141, CPU_OSVM, CPU_ALL, }, | 219 | { 0xC0010061, 0xC0010068, CPU_SMM, CPU_K10_PLUS, }, |
| 217 | { 0xc0010156, 0xc0010156, CPU_SMM, CPU_ALL, }, | 220 | { 0xC0010069, 0xC001006B, CPU_SMM, CPU_AMD_11, }, |
| 221 | { 0xC0010070, 0xC0010071, CPU_SMM, CPU_K10_PLUS, }, | ||
| 222 | { 0xC0010111, 0xC0010113, CPU_SMM, CPU_K8_PLUS, }, | ||
| 223 | { 0xC0010114, 0xC0010118, CPU_SVM, CPU_K10_PLUS, }, | ||
| 224 | { 0xC0010140, 0xC0010141, CPU_OSVM, CPU_K10_PLUS, }, | ||
| 225 | { 0xC0011022, 0xC0011023, CPU_CONF, CPU_K10_PLUS, }, | ||
| 218 | }; | 226 | }; |
| 219 | 227 | ||
| 220 | 228 | ||
| 221 | static int get_cpu_modelflag(unsigned cpu) | 229 | /* Intel */ |
| 230 | static int get_intel_modelflag(unsigned model) | ||
| 222 | { | 231 | { |
| 223 | int flag; | 232 | int flag; |
| 224 | 233 | ||
| 225 | switch (per_cpu(cpu_model, cpu)) { | 234 | switch (model) { |
| 226 | /* Intel */ | ||
| 227 | case 0x0501: | 235 | case 0x0501: |
| 228 | case 0x0502: | 236 | case 0x0502: |
| 229 | case 0x0504: | 237 | case 0x0504: |
| @@ -270,6 +278,59 @@ static int get_cpu_modelflag(unsigned cpu) | |||
| 270 | return flag; | 278 | return flag; |
| 271 | } | 279 | } |
| 272 | 280 | ||
| 281 | /* AMD */ | ||
| 282 | static int get_amd_modelflag(unsigned model) | ||
| 283 | { | ||
| 284 | int flag; | ||
| 285 | |||
| 286 | switch (model >> 8) { | ||
| 287 | case 0x6: | ||
| 288 | flag = CPU_AMD_K6; | ||
| 289 | break; | ||
| 290 | case 0x7: | ||
| 291 | flag = CPU_AMD_K7; | ||
| 292 | break; | ||
| 293 | case 0x8: | ||
| 294 | flag = CPU_AMD_K8; | ||
| 295 | break; | ||
| 296 | case 0xf: | ||
| 297 | flag = CPU_AMD_0F; | ||
| 298 | break; | ||
| 299 | case 0x10: | ||
| 300 | flag = CPU_AMD_10; | ||
| 301 | break; | ||
| 302 | case 0x11: | ||
| 303 | flag = CPU_AMD_11; | ||
| 304 | break; | ||
| 305 | default: | ||
| 306 | flag = CPU_NONE; | ||
| 307 | break; | ||
| 308 | } | ||
| 309 | |||
| 310 | return flag; | ||
| 311 | } | ||
| 312 | |||
| 313 | static int get_cpu_modelflag(unsigned cpu) | ||
| 314 | { | ||
| 315 | int flag; | ||
| 316 | |||
| 317 | flag = per_cpu(cpu_model, cpu); | ||
| 318 | |||
| 319 | switch (flag >> 16) { | ||
| 320 | case X86_VENDOR_INTEL: | ||
| 321 | flag = get_intel_modelflag(flag); | ||
| 322 | break; | ||
| 323 | case X86_VENDOR_AMD: | ||
| 324 | flag = get_amd_modelflag(flag & 0xffff); | ||
| 325 | break; | ||
| 326 | default: | ||
| 327 | flag = CPU_NONE; | ||
| 328 | break; | ||
| 329 | } | ||
| 330 | |||
| 331 | return flag; | ||
| 332 | } | ||
| 333 | |||
| 273 | static int get_cpu_range_count(unsigned cpu) | 334 | static int get_cpu_range_count(unsigned cpu) |
| 274 | { | 335 | { |
| 275 | int index; | 336 | int index; |
| @@ -310,7 +371,8 @@ static int is_typeflag_valid(unsigned cpu, unsigned flag) | |||
| 310 | return 1; | 371 | return 1; |
| 311 | break; | 372 | break; |
| 312 | case X86_VENDOR_AMD: | 373 | case X86_VENDOR_AMD: |
| 313 | if (cpu_amd_range[i].flag & flag) | 374 | if ((cpu_amd_range[i].model & modelflag) && |
| 375 | (cpu_amd_range[i].flag & flag)) | ||
| 314 | return 1; | 376 | return 1; |
| 315 | break; | 377 | break; |
| 316 | } | 378 | } |
| @@ -336,7 +398,8 @@ static unsigned get_cpu_range(unsigned cpu, unsigned *min, unsigned *max, | |||
| 336 | } | 398 | } |
| 337 | break; | 399 | break; |
| 338 | case X86_VENDOR_AMD: | 400 | case X86_VENDOR_AMD: |
| 339 | if (cpu_amd_range[index].flag & flag) { | 401 | if ((cpu_amd_range[index].model & modelflag) && |
| 402 | (cpu_amd_range[index].flag & flag)) { | ||
| 340 | *min = cpu_amd_range[index].min; | 403 | *min = cpu_amd_range[index].min; |
| 341 | *max = cpu_amd_range[index].max; | 404 | *max = cpu_amd_range[index].max; |
| 342 | } | 405 | } |
| @@ -608,9 +671,62 @@ static int cpu_seq_open(struct inode *inode, struct file *file) | |||
| 608 | return err; | 671 | return err; |
| 609 | } | 672 | } |
| 610 | 673 | ||
| 674 | static int write_msr(struct cpu_private *priv, u64 val) | ||
| 675 | { | ||
| 676 | u32 low, high; | ||
| 677 | |||
| 678 | high = (val >> 32) & 0xffffffff; | ||
| 679 | low = val & 0xffffffff; | ||
| 680 | |||
| 681 | if (!wrmsr_safe_on_cpu(priv->cpu, priv->reg, low, high)) | ||
| 682 | return 0; | ||
| 683 | |||
| 684 | return -EPERM; | ||
| 685 | } | ||
| 686 | |||
| 687 | static int write_cpu_register(struct cpu_private *priv, const char *buf) | ||
| 688 | { | ||
| 689 | int ret = -EPERM; | ||
| 690 | u64 val; | ||
| 691 | |||
| 692 | ret = strict_strtoull(buf, 0, &val); | ||
| 693 | if (ret < 0) | ||
| 694 | return ret; | ||
| 695 | |||
| 696 | /* Supporting only MSRs */ | ||
| 697 | if (priv->type < CPU_TSS_BIT) | ||
| 698 | return write_msr(priv, val); | ||
| 699 | |||
| 700 | return ret; | ||
| 701 | } | ||
| 702 | |||
| 703 | static ssize_t cpu_write(struct file *file, const char __user *ubuf, | ||
| 704 | size_t count, loff_t *off) | ||
| 705 | { | ||
| 706 | struct seq_file *seq = file->private_data; | ||
| 707 | struct cpu_private *priv = seq->private; | ||
| 708 | char buf[19]; | ||
| 709 | |||
| 710 | if ((priv == NULL) || (count >= sizeof(buf))) | ||
| 711 | return -EINVAL; | ||
| 712 | |||
| 713 | if (copy_from_user(&buf, ubuf, count)) | ||
| 714 | return -EFAULT; | ||
| 715 | |||
| 716 | buf[count] = 0; | ||
| 717 | |||
| 718 | if ((cpu_base[priv->type].write) && (cpu_file[priv->file].write)) | ||
| 719 | if (!write_cpu_register(priv, buf)) | ||
| 720 | return count; | ||
| 721 | |||
| 722 | return -EACCES; | ||
| 723 | } | ||
| 724 | |||
| 611 | static const struct file_operations cpu_fops = { | 725 | static const struct file_operations cpu_fops = { |
| 726 | .owner = THIS_MODULE, | ||
| 612 | .open = cpu_seq_open, | 727 | .open = cpu_seq_open, |
| 613 | .read = seq_read, | 728 | .read = seq_read, |
| 729 | .write = cpu_write, | ||
| 614 | .llseek = seq_lseek, | 730 | .llseek = seq_lseek, |
| 615 | .release = seq_release, | 731 | .release = seq_release, |
| 616 | }; | 732 | }; |
