-
Notifications
You must be signed in to change notification settings - Fork 26
/
msr_version.c
134 lines (119 loc) · 2.97 KB
/
msr_version.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
134
// Copyright 2011-2021 Lawrence Livermore National Security, LLC and other
// msr-safe Project Developers. See the top-level COPYRIGHT file for
// details.
//
// SPDX-License-Identifier: GPL-2.0-only
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/version.h>
#include <linux/module.h>
#include <linux/uaccess.h>
static struct class *cdev_class;
static char cdev_created;
static char cdev_registered;
static char cdev_class_created;
static int open_version(struct inode *inode, struct file *file)
{
return 0;
}
static ssize_t read_version(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
size_t len = strlen( THIS_MODULE->version ) + 1 < count ?
strlen( THIS_MODULE->version ) + 1 :
count;
if (*ppos > 0)
{
return 0;
}
if (len > count)
{
return -EFAULT;
}
if (copy_to_user(buf, THIS_MODULE->version, len))
{
return -EFAULT;
}
*ppos = 1;
return len;
}
static const struct file_operations fops =
{
.owner = THIS_MODULE,
.read = read_version,
.open = open_version
};
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,39)
static char *msr_version_nodename(struct device *dev, mode_t *mode)
#else
#if LINUX_VERSION_CODE <= KERNEL_VERSION(6,2,0)
static char *msr_version_nodename(struct device *dev, umode_t *mode)
#else
static char *msr_version_nodename(const struct device *dev, umode_t *mode)
#endif
#endif
{
if (mode)
{
*mode = 0400; // read-only
}
return kasprintf(GFP_KERNEL, "cpu/msr_safe_version");
}
void msr_version_cleanup(int majordev)
{
if (cdev_created)
{
cdev_created = 0;
device_destroy(cdev_class, MKDEV(majordev, 0));
}
if (cdev_class_created)
{
cdev_class_created = 0;
class_destroy(cdev_class);
}
if (cdev_registered)
{
cdev_registered = 0;
unregister_chrdev(majordev, "cpu/msr_safe_version");
}
}
int msr_version_init(int *majordev)
{
int err = 0;
struct device *dev;
err = register_chrdev(*majordev, "cpu/msr_safe_version", &fops);
if (err < 0)
{
pr_debug("%s: unable to register chrdev\n", __FUNCTION__);
msr_version_cleanup(*majordev);
err = -EBUSY;
return err;
}
if (err > 0)
{
*majordev = err;
}
cdev_registered = 1;
cdev_class = class_create(
#if LINUX_VERSION_CODE < KERNEL_VERSION(6,4,0)
THIS_MODULE,
#endif
"msr_safe_version");
if (IS_ERR(cdev_class))
{
err = PTR_ERR(cdev_class);
msr_version_cleanup(*majordev);
return err;
}
cdev_class_created = 1;
cdev_class->devnode = msr_version_nodename;
dev = device_create(cdev_class, NULL, MKDEV(*majordev, 0), NULL, "msr_safe_version");
if (IS_ERR(dev))
{
err = PTR_ERR(dev);
msr_version_cleanup(*majordev);
return err;
}
cdev_created = 1;
return 0;
}