Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/x86/lib/msr.c
49968 views
1
// SPDX-License-Identifier: GPL-2.0
2
#include <linux/export.h>
3
#include <linux/kvm_types.h>
4
#include <linux/percpu.h>
5
#include <linux/preempt.h>
6
#include <asm/msr.h>
7
#define CREATE_TRACE_POINTS
8
#include <asm/msr-trace.h>
9
10
struct msr __percpu *msrs_alloc(void)
11
{
12
struct msr __percpu *msrs = NULL;
13
14
msrs = alloc_percpu(struct msr);
15
if (!msrs) {
16
pr_warn("%s: error allocating msrs\n", __func__);
17
return NULL;
18
}
19
20
return msrs;
21
}
22
EXPORT_SYMBOL(msrs_alloc);
23
24
void msrs_free(struct msr __percpu *msrs)
25
{
26
free_percpu(msrs);
27
}
28
EXPORT_SYMBOL(msrs_free);
29
30
/**
31
* msr_read - Read an MSR with error handling
32
* @msr: MSR to read
33
* @m: value to read into
34
*
35
* It returns read data only on success, otherwise it doesn't change the output
36
* argument @m.
37
*
38
* Return: %0 for success, otherwise an error code
39
*/
40
static int msr_read(u32 msr, struct msr *m)
41
{
42
int err;
43
u64 val;
44
45
err = rdmsrq_safe(msr, &val);
46
if (!err)
47
m->q = val;
48
49
return err;
50
}
51
52
/**
53
* msr_write - Write an MSR with error handling
54
*
55
* @msr: MSR to write
56
* @m: value to write
57
*
58
* Return: %0 for success, otherwise an error code
59
*/
60
static int msr_write(u32 msr, struct msr *m)
61
{
62
return wrmsrq_safe(msr, m->q);
63
}
64
65
static inline int __flip_bit(u32 msr, u8 bit, bool set)
66
{
67
struct msr m, m1;
68
int err = -EINVAL;
69
70
if (bit > 63)
71
return err;
72
73
err = msr_read(msr, &m);
74
if (err)
75
return err;
76
77
m1 = m;
78
if (set)
79
m1.q |= BIT_64(bit);
80
else
81
m1.q &= ~BIT_64(bit);
82
83
if (m1.q == m.q)
84
return 0;
85
86
err = msr_write(msr, &m1);
87
if (err)
88
return err;
89
90
return 1;
91
}
92
93
/**
94
* msr_set_bit - Set @bit in a MSR @msr.
95
* @msr: MSR to write
96
* @bit: bit number to set
97
*
98
* Return:
99
* * < 0: An error was encountered.
100
* * = 0: Bit was already set.
101
* * > 0: Hardware accepted the MSR write.
102
*/
103
int msr_set_bit(u32 msr, u8 bit)
104
{
105
return __flip_bit(msr, bit, true);
106
}
107
EXPORT_SYMBOL_FOR_KVM(msr_set_bit);
108
109
/**
110
* msr_clear_bit - Clear @bit in a MSR @msr.
111
* @msr: MSR to write
112
* @bit: bit number to clear
113
*
114
* Return:
115
* * < 0: An error was encountered.
116
* * = 0: Bit was already cleared.
117
* * > 0: Hardware accepted the MSR write.
118
*/
119
int msr_clear_bit(u32 msr, u8 bit)
120
{
121
return __flip_bit(msr, bit, false);
122
}
123
EXPORT_SYMBOL_FOR_KVM(msr_clear_bit);
124
125
#ifdef CONFIG_TRACEPOINTS
126
void do_trace_write_msr(u32 msr, u64 val, int failed)
127
{
128
trace_write_msr(msr, val, failed);
129
}
130
EXPORT_SYMBOL(do_trace_write_msr);
131
EXPORT_TRACEPOINT_SYMBOL(write_msr);
132
133
void do_trace_read_msr(u32 msr, u64 val, int failed)
134
{
135
trace_read_msr(msr, val, failed);
136
}
137
EXPORT_SYMBOL(do_trace_read_msr);
138
EXPORT_TRACEPOINT_SYMBOL(read_msr);
139
140
void do_trace_rdpmc(u32 msr, u64 val, int failed)
141
{
142
trace_rdpmc(msr, val, failed);
143
}
144
EXPORT_SYMBOL(do_trace_rdpmc);
145
EXPORT_TRACEPOINT_SYMBOL(rdpmc);
146
147
#endif
148
149