-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsysfs-msrs.c
133 lines (110 loc) · 2.81 KB
/
sysfs-msrs.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/kobject.h>
#include <linux/cpu.h>
#include <linux/slab.h>
#include <asm/msr.h>
#include <asm/processor.h>
#define CPUID_EDX_MSR_SUPPORT (1 << 5)
struct msr_def {
u32 addr;
char *name;
struct kobj_attribute attr;
};
struct msr_kobj_container {
u8 valid;
struct kobject kobj;
struct device *cpu;
};
static struct kobj_type sysfs_msrs_ktype = {
.sysfs_ops = &kobj_sysfs_ops
};
static DEFINE_PER_CPU(struct msr_kobj_container*, msr_kobjs);
#define MSR_FUNCS(_addr, _name) \
static ssize_t show_msr_##_name(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { \
struct msr_kobj_container *c = container_of(kobj, struct msr_kobj_container, kobj); \
u32 l, h; \
\
if(rdmsr_safe_on_cpu(c->cpu->id, _addr, &l, &h)) { \
return -EIO; \
} \
\
if(h != 0) \
return sprintf(buf, "%x%x\n", h, l); \
else \
return sprintf(buf, "%x\n", l); \
} \
\
static ssize_t store_msr_##_name(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) { \
struct msr_kobj_container *c = container_of(kobj, struct msr_kobj_container, kobj); \
u64 v; \
int ret; \
\
ret = kstrtou64(buf, 0, &v); \
if(ret) \
return ret; \
\
if(wrmsr_safe_on_cpu(c->cpu->id, _addr, (u32) (v & 0xFFFFFFFFll), (u32) ((v & 0xFFFFFFFF00000000ll) >> 32))) { \
return -EIO; \
} \
\
return count; \
}
#include "msrs.h"
static void _deref_kobjs(void) {
int i;
for(i = 0; i < NR_CPUS; i++) {
struct msr_kobj_container *c = per_cpu(msr_kobjs, i);
if(c->valid)
kobject_put(&c->kobj);
}
}
static int __init sysfs_msrs_init(void) {
unsigned int eax, ebx, ecx, edx;
int i;
cpuid(0x01, &eax, &ebx, &ecx, &edx);
if((edx & CPUID_EDX_MSR_SUPPORT) == 0) {
pr_warn("RDMSR not supported\n");
return -ENODEV;
}
for(i = 0; i < NR_CPUS; i++) {
per_cpu(msr_kobjs, i) = kzalloc(sizeof(struct msr_kobj_container), GFP_KERNEL);
}
for(i = 0; i < NR_CPUS; i++) {
int j;
struct msr_kobj_container *c = per_cpu(msr_kobjs, i);
struct device *cpu = get_cpu_device(i);
if(cpu == NULL) {
continue;
}
c->cpu = cpu;
if(kobject_init_and_add(&c->kobj, &sysfs_msrs_ktype, &cpu->kobj, "msrs")) {
_deref_kobjs();
return -ENOMEM;
}
c->valid = 1;
for(j = 0;; j++) {
u32 l, h;
struct msr_def *msr = &msrs[j];
if(msr->addr == 0x0)
break;
if(rdmsr_safe_on_cpu(i, msr->addr, &l, &h)) {
continue;
}
if(sysfs_create_file(&c->kobj, &msr->attr.attr)) {
_deref_kobjs();
return -ENOMEM;
}
}
}
return 0;
}
module_init(sysfs_msrs_init);
static void __exit sysfs_msrs_exit(void) {
_deref_kobjs();
}
module_exit(sysfs_msrs_exit);
MODULE_AUTHOR("Yussuf Khalil <[email protected]>");
MODULE_DESCRIPTION("Expose x86 CPU MSRs to sysfs");
MODULE_LICENSE("GPL");