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