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
msrs_alloc(void)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
msrs_free(struct msr __percpu * msrs)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 */
msr_read(u32 msr,struct msr * m)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 */
msr_write(u32 msr,struct msr * m)60 static int msr_write(u32 msr, struct msr *m)
61 {
62 return wrmsrq_safe(msr, m->q);
63 }
64
__flip_bit(u32 msr,u8 bit,bool set)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 */
msr_set_bit(u32 msr,u8 bit)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 */
msr_clear_bit(u32 msr,u8 bit)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
do_trace_write_msr(u32 msr,u64 val,int failed)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
do_trace_read_msr(u32 msr,u64 val,int failed)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
do_trace_rdpmc(u32 msr,u64 val,int failed)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