]>
Commit | Line | Data |
---|---|---|
e08cae41 PA |
1 | #ifndef _ASM_X86_MSHYPER_H |
2 | #define _ASM_X86_MSHYPER_H | |
a2a47c6c | 3 | |
e08cae41 | 4 | #include <linux/types.h> |
26fcd952 | 5 | #include <linux/atomic.h> |
e08cae41 PA |
6 | #include <asm/hyperv.h> |
7 | ||
8de8af7e S |
8 | /* |
9 | * The below CPUID leaves are present if VersionAndFeatures.HypervisorPresent | |
10 | * is set by CPUID(HVCPUID_VERSION_FEATURES). | |
11 | */ | |
12 | enum hv_cpuid_function { | |
13 | HVCPUID_VERSION_FEATURES = 0x00000001, | |
14 | HVCPUID_VENDOR_MAXFUNCTION = 0x40000000, | |
15 | HVCPUID_INTERFACE = 0x40000001, | |
16 | ||
17 | /* | |
18 | * The remaining functions depend on the value of | |
19 | * HVCPUID_INTERFACE | |
20 | */ | |
21 | HVCPUID_VERSION = 0x40000002, | |
22 | HVCPUID_FEATURES = 0x40000003, | |
23 | HVCPUID_ENLIGHTENMENT_INFO = 0x40000004, | |
24 | HVCPUID_IMPLEMENTATION_LIMITS = 0x40000005, | |
25 | }; | |
26 | ||
e08cae41 PA |
27 | struct ms_hyperv_info { |
28 | u32 features; | |
cc2dd402 | 29 | u32 misc_features; |
e08cae41 PA |
30 | u32 hints; |
31 | }; | |
32 | ||
33 | extern struct ms_hyperv_info ms_hyperv; | |
a2a47c6c | 34 | |
3f646ed7 S |
35 | /* |
36 | * Declare the MSR used to setup pages used to communicate with the hypervisor. | |
37 | */ | |
38 | union hv_x64_msr_hypercall_contents { | |
39 | u64 as_uint64; | |
40 | struct { | |
41 | u64 enable:1; | |
42 | u64 reserved:11; | |
43 | u64 guest_physical_address:52; | |
44 | }; | |
45 | }; | |
46 | ||
63ed4e0c S |
47 | /* |
48 | * TSC page layout. | |
49 | */ | |
50 | ||
51 | struct ms_hyperv_tsc_page { | |
52 | volatile u32 tsc_sequence; | |
53 | u32 reserved1; | |
54 | volatile u64 tsc_scale; | |
55 | volatile s64 tsc_offset; | |
56 | u64 reserved2[509]; | |
57 | }; | |
58 | ||
352c9624 S |
59 | /* |
60 | * The guest OS needs to register the guest ID with the hypervisor. | |
61 | * The guest ID is a 64 bit entity and the structure of this ID is | |
62 | * specified in the Hyper-V specification: | |
63 | * | |
64 | * msdn.microsoft.com/en-us/library/windows/hardware/ff542653%28v=vs.85%29.aspx | |
65 | * | |
66 | * While the current guideline does not specify how Linux guest ID(s) | |
67 | * need to be generated, our plan is to publish the guidelines for | |
68 | * Linux and other guest operating systems that currently are hosted | |
69 | * on Hyper-V. The implementation here conforms to this yet | |
70 | * unpublished guidelines. | |
71 | * | |
72 | * | |
73 | * Bit(s) | |
74 | * 63 - Indicates if the OS is Open Source or not; 1 is Open Source | |
75 | * 62:56 - Os Type; Linux is 0x100 | |
76 | * 55:48 - Distro specific identification | |
77 | * 47:16 - Linux kernel version number | |
78 | * 15:0 - Distro specific identification | |
79 | * | |
80 | * | |
81 | */ | |
82 | ||
9b06e101 | 83 | #define HV_LINUX_VENDOR_ID 0x8100 |
352c9624 S |
84 | |
85 | /* | |
86 | * Generate the guest ID based on the guideline described above. | |
87 | */ | |
88 | ||
89 | static inline __u64 generate_guest_id(__u64 d_info1, __u64 kernel_version, | |
90 | __u64 d_info2) | |
91 | { | |
92 | __u64 guest_id = 0; | |
93 | ||
9b06e101 | 94 | guest_id = (((__u64)HV_LINUX_VENDOR_ID) << 48); |
352c9624 S |
95 | guest_id |= (d_info1 << 48); |
96 | guest_id |= (kernel_version << 16); | |
97 | guest_id |= d_info2; | |
98 | ||
99 | return guest_id; | |
100 | } | |
101 | ||
e810e48c S |
102 | |
103 | /* Free the message slot and signal end-of-message if required */ | |
104 | static inline void vmbus_signal_eom(struct hv_message *msg, u32 old_msg_type) | |
105 | { | |
106 | /* | |
107 | * On crash we're reading some other CPU's message page and we need | |
108 | * to be careful: this other CPU may already had cleared the header | |
109 | * and the host may already had delivered some other message there. | |
110 | * In case we blindly write msg->header.message_type we're going | |
111 | * to lose it. We can still lose a message of the same type but | |
112 | * we count on the fact that there can only be one | |
113 | * CHANNELMSG_UNLOAD_RESPONSE and we don't care about other messages | |
114 | * on crash. | |
115 | */ | |
116 | if (cmpxchg(&msg->header.message_type, old_msg_type, | |
117 | HVMSG_NONE) != old_msg_type) | |
118 | return; | |
119 | ||
120 | /* | |
121 | * Make sure the write to MessageType (ie set to | |
122 | * HVMSG_NONE) happens before we read the | |
123 | * MessagePending and EOMing. Otherwise, the EOMing | |
124 | * will not deliver any more messages since there is | |
125 | * no empty slot | |
126 | */ | |
127 | mb(); | |
128 | ||
129 | if (msg->header.message_flags.msg_pending) { | |
130 | /* | |
131 | * This will cause message queue rescan to | |
132 | * possibly deliver another msg from the | |
133 | * hypervisor | |
134 | */ | |
135 | wrmsrl(HV_X64_MSR_EOM, 0); | |
136 | } | |
137 | } | |
138 | ||
d5116b40 S |
139 | #define hv_init_timer(timer, tick) wrmsrl(timer, tick) |
140 | #define hv_init_timer_config(config, val) wrmsrl(config, val) | |
141 | ||
155e4a2f S |
142 | #define hv_get_simp(val) rdmsrl(HV_X64_MSR_SIMP, val) |
143 | #define hv_set_simp(val) wrmsrl(HV_X64_MSR_SIMP, val) | |
144 | ||
8e307bf8 S |
145 | #define hv_get_siefp(val) rdmsrl(HV_X64_MSR_SIEFP, val) |
146 | #define hv_set_siefp(val) wrmsrl(HV_X64_MSR_SIEFP, val) | |
147 | ||
06d1d98a S |
148 | #define hv_get_synic_state(val) rdmsrl(HV_X64_MSR_SCONTROL, val) |
149 | #define hv_set_synic_state(val) wrmsrl(HV_X64_MSR_SCONTROL, val) | |
150 | ||
7297ff0c S |
151 | #define hv_get_vp_index(index) rdmsrl(HV_X64_MSR_VP_INDEX, index) |
152 | ||
37e11d5c S |
153 | #define hv_get_synint_state(int_num, val) rdmsrl(int_num, val) |
154 | #define hv_set_synint_state(int_num, val) wrmsrl(int_num, val) | |
155 | ||
bc2b0331 | 156 | void hyperv_callback_vector(void); |
cf910e83 SA |
157 | #ifdef CONFIG_TRACING |
158 | #define trace_hyperv_callback_vector hyperv_callback_vector | |
159 | #endif | |
bc2b0331 | 160 | void hyperv_vector_handler(struct pt_regs *regs); |
76d388cd TG |
161 | void hv_setup_vmbus_irq(void (*handler)(void)); |
162 | void hv_remove_vmbus_irq(void); | |
bc2b0331 | 163 | |
2517281d VK |
164 | void hv_setup_kexec_handler(void (*handler)(void)); |
165 | void hv_remove_kexec_handler(void); | |
b4370df2 VK |
166 | void hv_setup_crash_handler(void (*handler)(struct pt_regs *regs)); |
167 | void hv_remove_crash_handler(void); | |
8730046c S |
168 | |
169 | #if IS_ENABLED(CONFIG_HYPERV) | |
dee863b5 VK |
170 | extern struct clocksource *hyperv_cs; |
171 | ||
8730046c | 172 | void hyperv_init(void); |
d058fa7e | 173 | void hyperv_report_panic(struct pt_regs *regs); |
73638cdd | 174 | bool hv_is_hypercall_page_setup(void); |
d6f3609d | 175 | void hyperv_cleanup(void); |
8730046c | 176 | #endif |
bd2a9ada VK |
177 | #ifdef CONFIG_HYPERV_TSCPAGE |
178 | struct ms_hyperv_tsc_page *hv_get_tsc_page(void); | |
0733379b VK |
179 | static inline u64 hv_read_tsc_page(const struct ms_hyperv_tsc_page *tsc_pg) |
180 | { | |
181 | u64 scale, offset, cur_tsc; | |
182 | u32 sequence; | |
183 | ||
184 | /* | |
185 | * The protocol for reading Hyper-V TSC page is specified in Hypervisor | |
186 | * Top-Level Functional Specification ver. 3.0 and above. To get the | |
187 | * reference time we must do the following: | |
188 | * - READ ReferenceTscSequence | |
189 | * A special '0' value indicates the time source is unreliable and we | |
190 | * need to use something else. The currently published specification | |
191 | * versions (up to 4.0b) contain a mistake and wrongly claim '-1' | |
192 | * instead of '0' as the special value, see commit c35b82ef0294. | |
193 | * - ReferenceTime = | |
194 | * ((RDTSC() * ReferenceTscScale) >> 64) + ReferenceTscOffset | |
195 | * - READ ReferenceTscSequence again. In case its value has changed | |
196 | * since our first reading we need to discard ReferenceTime and repeat | |
197 | * the whole sequence as the hypervisor was updating the page in | |
198 | * between. | |
199 | */ | |
200 | do { | |
201 | sequence = READ_ONCE(tsc_pg->tsc_sequence); | |
202 | if (!sequence) | |
203 | return U64_MAX; | |
204 | /* | |
205 | * Make sure we read sequence before we read other values from | |
206 | * TSC page. | |
207 | */ | |
208 | smp_rmb(); | |
209 | ||
210 | scale = READ_ONCE(tsc_pg->tsc_scale); | |
211 | offset = READ_ONCE(tsc_pg->tsc_offset); | |
212 | cur_tsc = rdtsc_ordered(); | |
213 | ||
214 | /* | |
215 | * Make sure we read sequence after we read all other values | |
216 | * from TSC page. | |
217 | */ | |
218 | smp_rmb(); | |
219 | ||
220 | } while (READ_ONCE(tsc_pg->tsc_sequence) != sequence); | |
221 | ||
222 | return mul_u64_u64_shr(cur_tsc, scale, 64) + offset; | |
223 | } | |
224 | ||
bd2a9ada VK |
225 | #else |
226 | static inline struct ms_hyperv_tsc_page *hv_get_tsc_page(void) | |
227 | { | |
228 | return NULL; | |
229 | } | |
230 | #endif | |
a2a47c6c | 231 | #endif |