xref: /linux/arch/x86/include/asm/mshyperv.h (revision 6523592cee4650c6aa997d69cd0045a01e07a1ef)
1 /* SPDX-License-Identifier: GPL-2.0 */
2 #ifndef _ASM_X86_MSHYPER_H
3 #define _ASM_X86_MSHYPER_H
4 
5 #include <linux/types.h>
6 #include <linux/nmi.h>
7 #include <linux/msi.h>
8 #include <asm/io.h>
9 #include <asm/hyperv-tlfs.h>
10 #include <asm/nospec-branch.h>
11 #include <asm/paravirt.h>
12 
13 typedef int (*hyperv_fill_flush_list_func)(
14 		struct hv_guest_mapping_flush_list *flush,
15 		void *data);
16 
17 static inline void hv_set_register(unsigned int reg, u64 value)
18 {
19 	wrmsrl(reg, value);
20 }
21 
22 static inline u64 hv_get_register(unsigned int reg)
23 {
24 	u64 value;
25 
26 	rdmsrl(reg, value);
27 	return value;
28 }
29 
30 #define hv_get_raw_timer() rdtsc_ordered()
31 
32 void hyperv_vector_handler(struct pt_regs *regs);
33 
34 #if IS_ENABLED(CONFIG_HYPERV)
35 extern int hyperv_init_cpuhp;
36 
37 extern void *hv_hypercall_pg;
38 extern void  __percpu  **hyperv_pcpu_input_arg;
39 extern void  __percpu  **hyperv_pcpu_output_arg;
40 
41 extern u64 hv_current_partition_id;
42 
43 int hv_call_deposit_pages(int node, u64 partition_id, u32 num_pages);
44 int hv_call_add_logical_proc(int node, u32 lp_index, u32 acpi_id);
45 int hv_call_create_vp(int node, u64 partition_id, u32 vp_index, u32 flags);
46 
47 static inline u64 hv_do_hypercall(u64 control, void *input, void *output)
48 {
49 	u64 input_address = input ? virt_to_phys(input) : 0;
50 	u64 output_address = output ? virt_to_phys(output) : 0;
51 	u64 hv_status;
52 
53 #ifdef CONFIG_X86_64
54 	if (!hv_hypercall_pg)
55 		return U64_MAX;
56 
57 	__asm__ __volatile__("mov %4, %%r8\n"
58 			     CALL_NOSPEC
59 			     : "=a" (hv_status), ASM_CALL_CONSTRAINT,
60 			       "+c" (control), "+d" (input_address)
61 			     :  "r" (output_address),
62 				THUNK_TARGET(hv_hypercall_pg)
63 			     : "cc", "memory", "r8", "r9", "r10", "r11");
64 #else
65 	u32 input_address_hi = upper_32_bits(input_address);
66 	u32 input_address_lo = lower_32_bits(input_address);
67 	u32 output_address_hi = upper_32_bits(output_address);
68 	u32 output_address_lo = lower_32_bits(output_address);
69 
70 	if (!hv_hypercall_pg)
71 		return U64_MAX;
72 
73 	__asm__ __volatile__(CALL_NOSPEC
74 			     : "=A" (hv_status),
75 			       "+c" (input_address_lo), ASM_CALL_CONSTRAINT
76 			     : "A" (control),
77 			       "b" (input_address_hi),
78 			       "D"(output_address_hi), "S"(output_address_lo),
79 			       THUNK_TARGET(hv_hypercall_pg)
80 			     : "cc", "memory");
81 #endif /* !x86_64 */
82 	return hv_status;
83 }
84 
85 /* Fast hypercall with 8 bytes of input and no output */
86 static inline u64 hv_do_fast_hypercall8(u16 code, u64 input1)
87 {
88 	u64 hv_status, control = (u64)code | HV_HYPERCALL_FAST_BIT;
89 
90 #ifdef CONFIG_X86_64
91 	{
92 		__asm__ __volatile__(CALL_NOSPEC
93 				     : "=a" (hv_status), ASM_CALL_CONSTRAINT,
94 				       "+c" (control), "+d" (input1)
95 				     : THUNK_TARGET(hv_hypercall_pg)
96 				     : "cc", "r8", "r9", "r10", "r11");
97 	}
98 #else
99 	{
100 		u32 input1_hi = upper_32_bits(input1);
101 		u32 input1_lo = lower_32_bits(input1);
102 
103 		__asm__ __volatile__ (CALL_NOSPEC
104 				      : "=A"(hv_status),
105 					"+c"(input1_lo),
106 					ASM_CALL_CONSTRAINT
107 				      :	"A" (control),
108 					"b" (input1_hi),
109 					THUNK_TARGET(hv_hypercall_pg)
110 				      : "cc", "edi", "esi");
111 	}
112 #endif
113 		return hv_status;
114 }
115 
116 /* Fast hypercall with 16 bytes of input */
117 static inline u64 hv_do_fast_hypercall16(u16 code, u64 input1, u64 input2)
118 {
119 	u64 hv_status, control = (u64)code | HV_HYPERCALL_FAST_BIT;
120 
121 #ifdef CONFIG_X86_64
122 	{
123 		__asm__ __volatile__("mov %4, %%r8\n"
124 				     CALL_NOSPEC
125 				     : "=a" (hv_status), ASM_CALL_CONSTRAINT,
126 				       "+c" (control), "+d" (input1)
127 				     : "r" (input2),
128 				       THUNK_TARGET(hv_hypercall_pg)
129 				     : "cc", "r8", "r9", "r10", "r11");
130 	}
131 #else
132 	{
133 		u32 input1_hi = upper_32_bits(input1);
134 		u32 input1_lo = lower_32_bits(input1);
135 		u32 input2_hi = upper_32_bits(input2);
136 		u32 input2_lo = lower_32_bits(input2);
137 
138 		__asm__ __volatile__ (CALL_NOSPEC
139 				      : "=A"(hv_status),
140 					"+c"(input1_lo), ASM_CALL_CONSTRAINT
141 				      :	"A" (control), "b" (input1_hi),
142 					"D"(input2_hi), "S"(input2_lo),
143 					THUNK_TARGET(hv_hypercall_pg)
144 				      : "cc");
145 	}
146 #endif
147 	return hv_status;
148 }
149 
150 extern struct hv_vp_assist_page **hv_vp_assist_page;
151 
152 static inline struct hv_vp_assist_page *hv_get_vp_assist_page(unsigned int cpu)
153 {
154 	if (!hv_vp_assist_page)
155 		return NULL;
156 
157 	return hv_vp_assist_page[cpu];
158 }
159 
160 void __init hyperv_init(void);
161 void hyperv_setup_mmu_ops(void);
162 void set_hv_tscchange_cb(void (*cb)(void));
163 void clear_hv_tscchange_cb(void);
164 void hyperv_stop_tsc_emulation(void);
165 int hyperv_flush_guest_mapping(u64 as);
166 int hyperv_flush_guest_mapping_range(u64 as,
167 		hyperv_fill_flush_list_func fill_func, void *data);
168 int hyperv_fill_flush_guest_mapping_list(
169 		struct hv_guest_mapping_flush_list *flush,
170 		u64 start_gfn, u64 end_gfn);
171 
172 extern bool hv_root_partition;
173 
174 #ifdef CONFIG_X86_64
175 void hv_apic_init(void);
176 void __init hv_init_spinlocks(void);
177 bool hv_vcpu_is_preempted(int vcpu);
178 #else
179 static inline void hv_apic_init(void) {}
180 #endif
181 
182 static inline void hv_set_msi_entry_from_desc(union hv_msi_entry *msi_entry,
183 					      struct msi_desc *msi_desc)
184 {
185 	msi_entry->address.as_uint32 = msi_desc->msg.address_lo;
186 	msi_entry->data.as_uint32 = msi_desc->msg.data;
187 }
188 
189 struct irq_domain *hv_create_pci_msi_domain(void);
190 
191 int hv_map_ioapic_interrupt(int ioapic_id, bool level, int vcpu, int vector,
192 		struct hv_interrupt_entry *entry);
193 int hv_unmap_ioapic_interrupt(int ioapic_id, struct hv_interrupt_entry *entry);
194 
195 #else /* CONFIG_HYPERV */
196 static inline void hyperv_init(void) {}
197 static inline void hyperv_setup_mmu_ops(void) {}
198 static inline void set_hv_tscchange_cb(void (*cb)(void)) {}
199 static inline void clear_hv_tscchange_cb(void) {}
200 static inline void hyperv_stop_tsc_emulation(void) {};
201 static inline struct hv_vp_assist_page *hv_get_vp_assist_page(unsigned int cpu)
202 {
203 	return NULL;
204 }
205 static inline int hyperv_flush_guest_mapping(u64 as) { return -1; }
206 static inline int hyperv_flush_guest_mapping_range(u64 as,
207 		hyperv_fill_flush_list_func fill_func, void *data)
208 {
209 	return -1;
210 }
211 #endif /* CONFIG_HYPERV */
212 
213 
214 #include <asm-generic/mshyperv.h>
215 
216 #endif
217