xref: /linux/arch/x86/lib/msr.c (revision 7fc2cd2e4b398c57c9cf961cfea05eadbf34c05c)
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