xref: /openbmc/linux/arch/x86/kvm/hyperv.c (revision 9eec50b8bbe1535c440a1ee88c1958f78fc55957)
1e83d5887SAndrey Smetanin /*
2e83d5887SAndrey Smetanin  * KVM Microsoft Hyper-V emulation
3e83d5887SAndrey Smetanin  *
4e83d5887SAndrey Smetanin  * derived from arch/x86/kvm/x86.c
5e83d5887SAndrey Smetanin  *
6e83d5887SAndrey Smetanin  * Copyright (C) 2006 Qumranet, Inc.
7e83d5887SAndrey Smetanin  * Copyright (C) 2008 Qumranet, Inc.
8e83d5887SAndrey Smetanin  * Copyright IBM Corporation, 2008
9e83d5887SAndrey Smetanin  * Copyright 2010 Red Hat, Inc. and/or its affiliates.
10e83d5887SAndrey Smetanin  * Copyright (C) 2015 Andrey Smetanin <asmetanin@virtuozzo.com>
11e83d5887SAndrey Smetanin  *
12e83d5887SAndrey Smetanin  * Authors:
13e83d5887SAndrey Smetanin  *   Avi Kivity   <avi@qumranet.com>
14e83d5887SAndrey Smetanin  *   Yaniv Kamay  <yaniv@qumranet.com>
15e83d5887SAndrey Smetanin  *   Amit Shah    <amit.shah@qumranet.com>
16e83d5887SAndrey Smetanin  *   Ben-Ami Yassour <benami@il.ibm.com>
17e83d5887SAndrey Smetanin  *   Andrey Smetanin <asmetanin@virtuozzo.com>
18e83d5887SAndrey Smetanin  *
19e83d5887SAndrey Smetanin  * This work is licensed under the terms of the GNU GPL, version 2.  See
20e83d5887SAndrey Smetanin  * the COPYING file in the top-level directory.
21e83d5887SAndrey Smetanin  *
22e83d5887SAndrey Smetanin  */
23e83d5887SAndrey Smetanin 
24e83d5887SAndrey Smetanin #include "x86.h"
25e83d5887SAndrey Smetanin #include "lapic.h"
26e83d5887SAndrey Smetanin #include "hyperv.h"
27e83d5887SAndrey Smetanin 
28e83d5887SAndrey Smetanin #include <linux/kvm_host.h>
29e83d5887SAndrey Smetanin #include <trace/events/kvm.h>
30e83d5887SAndrey Smetanin 
31e83d5887SAndrey Smetanin #include "trace.h"
32e83d5887SAndrey Smetanin 
33e83d5887SAndrey Smetanin static bool kvm_hv_msr_partition_wide(u32 msr)
34e83d5887SAndrey Smetanin {
35e83d5887SAndrey Smetanin 	bool r = false;
36e83d5887SAndrey Smetanin 
37e83d5887SAndrey Smetanin 	switch (msr) {
38e83d5887SAndrey Smetanin 	case HV_X64_MSR_GUEST_OS_ID:
39e83d5887SAndrey Smetanin 	case HV_X64_MSR_HYPERCALL:
40e83d5887SAndrey Smetanin 	case HV_X64_MSR_REFERENCE_TSC:
41e83d5887SAndrey Smetanin 	case HV_X64_MSR_TIME_REF_COUNT:
42e7d9513bSAndrey Smetanin 	case HV_X64_MSR_CRASH_CTL:
43e7d9513bSAndrey Smetanin 	case HV_X64_MSR_CRASH_P0 ... HV_X64_MSR_CRASH_P4:
44e516cebbSAndrey Smetanin 	case HV_X64_MSR_RESET:
45e83d5887SAndrey Smetanin 		r = true;
46e83d5887SAndrey Smetanin 		break;
47e83d5887SAndrey Smetanin 	}
48e83d5887SAndrey Smetanin 
49e83d5887SAndrey Smetanin 	return r;
50e83d5887SAndrey Smetanin }
51e83d5887SAndrey Smetanin 
52e7d9513bSAndrey Smetanin static int kvm_hv_msr_get_crash_data(struct kvm_vcpu *vcpu,
53e7d9513bSAndrey Smetanin 				     u32 index, u64 *pdata)
54e7d9513bSAndrey Smetanin {
55e7d9513bSAndrey Smetanin 	struct kvm_hv *hv = &vcpu->kvm->arch.hyperv;
56e7d9513bSAndrey Smetanin 
57e7d9513bSAndrey Smetanin 	if (WARN_ON_ONCE(index >= ARRAY_SIZE(hv->hv_crash_param)))
58e7d9513bSAndrey Smetanin 		return -EINVAL;
59e7d9513bSAndrey Smetanin 
60e7d9513bSAndrey Smetanin 	*pdata = hv->hv_crash_param[index];
61e7d9513bSAndrey Smetanin 	return 0;
62e7d9513bSAndrey Smetanin }
63e7d9513bSAndrey Smetanin 
64e7d9513bSAndrey Smetanin static int kvm_hv_msr_get_crash_ctl(struct kvm_vcpu *vcpu, u64 *pdata)
65e7d9513bSAndrey Smetanin {
66e7d9513bSAndrey Smetanin 	struct kvm_hv *hv = &vcpu->kvm->arch.hyperv;
67e7d9513bSAndrey Smetanin 
68e7d9513bSAndrey Smetanin 	*pdata = hv->hv_crash_ctl;
69e7d9513bSAndrey Smetanin 	return 0;
70e7d9513bSAndrey Smetanin }
71e7d9513bSAndrey Smetanin 
72e7d9513bSAndrey Smetanin static int kvm_hv_msr_set_crash_ctl(struct kvm_vcpu *vcpu, u64 data, bool host)
73e7d9513bSAndrey Smetanin {
74e7d9513bSAndrey Smetanin 	struct kvm_hv *hv = &vcpu->kvm->arch.hyperv;
75e7d9513bSAndrey Smetanin 
76e7d9513bSAndrey Smetanin 	if (host)
77e7d9513bSAndrey Smetanin 		hv->hv_crash_ctl = data & HV_X64_MSR_CRASH_CTL_NOTIFY;
78e7d9513bSAndrey Smetanin 
79e7d9513bSAndrey Smetanin 	if (!host && (data & HV_X64_MSR_CRASH_CTL_NOTIFY)) {
80e7d9513bSAndrey Smetanin 
81e7d9513bSAndrey Smetanin 		vcpu_debug(vcpu, "hv crash (0x%llx 0x%llx 0x%llx 0x%llx 0x%llx)\n",
82e7d9513bSAndrey Smetanin 			  hv->hv_crash_param[0],
83e7d9513bSAndrey Smetanin 			  hv->hv_crash_param[1],
84e7d9513bSAndrey Smetanin 			  hv->hv_crash_param[2],
85e7d9513bSAndrey Smetanin 			  hv->hv_crash_param[3],
86e7d9513bSAndrey Smetanin 			  hv->hv_crash_param[4]);
87e7d9513bSAndrey Smetanin 
88e7d9513bSAndrey Smetanin 		/* Send notification about crash to user space */
89e7d9513bSAndrey Smetanin 		kvm_make_request(KVM_REQ_HV_CRASH, vcpu);
90e7d9513bSAndrey Smetanin 	}
91e7d9513bSAndrey Smetanin 
92e7d9513bSAndrey Smetanin 	return 0;
93e7d9513bSAndrey Smetanin }
94e7d9513bSAndrey Smetanin 
95e7d9513bSAndrey Smetanin static int kvm_hv_msr_set_crash_data(struct kvm_vcpu *vcpu,
96e7d9513bSAndrey Smetanin 				     u32 index, u64 data)
97e7d9513bSAndrey Smetanin {
98e7d9513bSAndrey Smetanin 	struct kvm_hv *hv = &vcpu->kvm->arch.hyperv;
99e7d9513bSAndrey Smetanin 
100e7d9513bSAndrey Smetanin 	if (WARN_ON_ONCE(index >= ARRAY_SIZE(hv->hv_crash_param)))
101e7d9513bSAndrey Smetanin 		return -EINVAL;
102e7d9513bSAndrey Smetanin 
103e7d9513bSAndrey Smetanin 	hv->hv_crash_param[index] = data;
104e7d9513bSAndrey Smetanin 	return 0;
105e7d9513bSAndrey Smetanin }
106e7d9513bSAndrey Smetanin 
107e7d9513bSAndrey Smetanin static int kvm_hv_set_msr_pw(struct kvm_vcpu *vcpu, u32 msr, u64 data,
108e7d9513bSAndrey Smetanin 			     bool host)
109e83d5887SAndrey Smetanin {
110e83d5887SAndrey Smetanin 	struct kvm *kvm = vcpu->kvm;
111e83d5887SAndrey Smetanin 	struct kvm_hv *hv = &kvm->arch.hyperv;
112e83d5887SAndrey Smetanin 
113e83d5887SAndrey Smetanin 	switch (msr) {
114e83d5887SAndrey Smetanin 	case HV_X64_MSR_GUEST_OS_ID:
115e83d5887SAndrey Smetanin 		hv->hv_guest_os_id = data;
116e83d5887SAndrey Smetanin 		/* setting guest os id to zero disables hypercall page */
117e83d5887SAndrey Smetanin 		if (!hv->hv_guest_os_id)
118e83d5887SAndrey Smetanin 			hv->hv_hypercall &= ~HV_X64_MSR_HYPERCALL_ENABLE;
119e83d5887SAndrey Smetanin 		break;
120e83d5887SAndrey Smetanin 	case HV_X64_MSR_HYPERCALL: {
121e83d5887SAndrey Smetanin 		u64 gfn;
122e83d5887SAndrey Smetanin 		unsigned long addr;
123e83d5887SAndrey Smetanin 		u8 instructions[4];
124e83d5887SAndrey Smetanin 
125e83d5887SAndrey Smetanin 		/* if guest os id is not set hypercall should remain disabled */
126e83d5887SAndrey Smetanin 		if (!hv->hv_guest_os_id)
127e83d5887SAndrey Smetanin 			break;
128e83d5887SAndrey Smetanin 		if (!(data & HV_X64_MSR_HYPERCALL_ENABLE)) {
129e83d5887SAndrey Smetanin 			hv->hv_hypercall = data;
130e83d5887SAndrey Smetanin 			break;
131e83d5887SAndrey Smetanin 		}
132e83d5887SAndrey Smetanin 		gfn = data >> HV_X64_MSR_HYPERCALL_PAGE_ADDRESS_SHIFT;
133e83d5887SAndrey Smetanin 		addr = gfn_to_hva(kvm, gfn);
134e83d5887SAndrey Smetanin 		if (kvm_is_error_hva(addr))
135e83d5887SAndrey Smetanin 			return 1;
136e83d5887SAndrey Smetanin 		kvm_x86_ops->patch_hypercall(vcpu, instructions);
137e83d5887SAndrey Smetanin 		((unsigned char *)instructions)[3] = 0xc3; /* ret */
138e83d5887SAndrey Smetanin 		if (__copy_to_user((void __user *)addr, instructions, 4))
139e83d5887SAndrey Smetanin 			return 1;
140e83d5887SAndrey Smetanin 		hv->hv_hypercall = data;
141e83d5887SAndrey Smetanin 		mark_page_dirty(kvm, gfn);
142e83d5887SAndrey Smetanin 		break;
143e83d5887SAndrey Smetanin 	}
144e83d5887SAndrey Smetanin 	case HV_X64_MSR_REFERENCE_TSC: {
145e83d5887SAndrey Smetanin 		u64 gfn;
146e83d5887SAndrey Smetanin 		HV_REFERENCE_TSC_PAGE tsc_ref;
147e83d5887SAndrey Smetanin 
148e83d5887SAndrey Smetanin 		memset(&tsc_ref, 0, sizeof(tsc_ref));
149e83d5887SAndrey Smetanin 		hv->hv_tsc_page = data;
150e83d5887SAndrey Smetanin 		if (!(data & HV_X64_MSR_TSC_REFERENCE_ENABLE))
151e83d5887SAndrey Smetanin 			break;
152e83d5887SAndrey Smetanin 		gfn = data >> HV_X64_MSR_TSC_REFERENCE_ADDRESS_SHIFT;
153e83d5887SAndrey Smetanin 		if (kvm_write_guest(
154e83d5887SAndrey Smetanin 				kvm,
155e83d5887SAndrey Smetanin 				gfn << HV_X64_MSR_TSC_REFERENCE_ADDRESS_SHIFT,
156e83d5887SAndrey Smetanin 				&tsc_ref, sizeof(tsc_ref)))
157e83d5887SAndrey Smetanin 			return 1;
158e83d5887SAndrey Smetanin 		mark_page_dirty(kvm, gfn);
159e83d5887SAndrey Smetanin 		break;
160e83d5887SAndrey Smetanin 	}
161e7d9513bSAndrey Smetanin 	case HV_X64_MSR_CRASH_P0 ... HV_X64_MSR_CRASH_P4:
162e7d9513bSAndrey Smetanin 		return kvm_hv_msr_set_crash_data(vcpu,
163e7d9513bSAndrey Smetanin 						 msr - HV_X64_MSR_CRASH_P0,
164e7d9513bSAndrey Smetanin 						 data);
165e7d9513bSAndrey Smetanin 	case HV_X64_MSR_CRASH_CTL:
166e7d9513bSAndrey Smetanin 		return kvm_hv_msr_set_crash_ctl(vcpu, data, host);
167e516cebbSAndrey Smetanin 	case HV_X64_MSR_RESET:
168e516cebbSAndrey Smetanin 		if (data == 1) {
169e516cebbSAndrey Smetanin 			vcpu_debug(vcpu, "hyper-v reset requested\n");
170e516cebbSAndrey Smetanin 			kvm_make_request(KVM_REQ_HV_RESET, vcpu);
171e516cebbSAndrey Smetanin 		}
172e516cebbSAndrey Smetanin 		break;
173e83d5887SAndrey Smetanin 	default:
174e83d5887SAndrey Smetanin 		vcpu_unimpl(vcpu, "Hyper-V uhandled wrmsr: 0x%x data 0x%llx\n",
175e83d5887SAndrey Smetanin 			    msr, data);
176e83d5887SAndrey Smetanin 		return 1;
177e83d5887SAndrey Smetanin 	}
178e83d5887SAndrey Smetanin 	return 0;
179e83d5887SAndrey Smetanin }
180e83d5887SAndrey Smetanin 
181*9eec50b8SAndrey Smetanin /* Calculate cpu time spent by current task in 100ns units */
182*9eec50b8SAndrey Smetanin static u64 current_task_runtime_100ns(void)
183*9eec50b8SAndrey Smetanin {
184*9eec50b8SAndrey Smetanin 	cputime_t utime, stime;
185*9eec50b8SAndrey Smetanin 
186*9eec50b8SAndrey Smetanin 	task_cputime_adjusted(current, &utime, &stime);
187*9eec50b8SAndrey Smetanin 	return div_u64(cputime_to_nsecs(utime + stime), 100);
188*9eec50b8SAndrey Smetanin }
189*9eec50b8SAndrey Smetanin 
190*9eec50b8SAndrey Smetanin static int kvm_hv_set_msr(struct kvm_vcpu *vcpu, u32 msr, u64 data, bool host)
191e83d5887SAndrey Smetanin {
192e83d5887SAndrey Smetanin 	struct kvm_vcpu_hv *hv = &vcpu->arch.hyperv;
193e83d5887SAndrey Smetanin 
194e83d5887SAndrey Smetanin 	switch (msr) {
195e83d5887SAndrey Smetanin 	case HV_X64_MSR_APIC_ASSIST_PAGE: {
196e83d5887SAndrey Smetanin 		u64 gfn;
197e83d5887SAndrey Smetanin 		unsigned long addr;
198e83d5887SAndrey Smetanin 
199e83d5887SAndrey Smetanin 		if (!(data & HV_X64_MSR_APIC_ASSIST_PAGE_ENABLE)) {
200e83d5887SAndrey Smetanin 			hv->hv_vapic = data;
201e83d5887SAndrey Smetanin 			if (kvm_lapic_enable_pv_eoi(vcpu, 0))
202e83d5887SAndrey Smetanin 				return 1;
203e83d5887SAndrey Smetanin 			break;
204e83d5887SAndrey Smetanin 		}
205e83d5887SAndrey Smetanin 		gfn = data >> HV_X64_MSR_APIC_ASSIST_PAGE_ADDRESS_SHIFT;
206e83d5887SAndrey Smetanin 		addr = kvm_vcpu_gfn_to_hva(vcpu, gfn);
207e83d5887SAndrey Smetanin 		if (kvm_is_error_hva(addr))
208e83d5887SAndrey Smetanin 			return 1;
209e83d5887SAndrey Smetanin 		if (__clear_user((void __user *)addr, PAGE_SIZE))
210e83d5887SAndrey Smetanin 			return 1;
211e83d5887SAndrey Smetanin 		hv->hv_vapic = data;
212e83d5887SAndrey Smetanin 		kvm_vcpu_mark_page_dirty(vcpu, gfn);
213e83d5887SAndrey Smetanin 		if (kvm_lapic_enable_pv_eoi(vcpu,
214e83d5887SAndrey Smetanin 					    gfn_to_gpa(gfn) | KVM_MSR_ENABLED))
215e83d5887SAndrey Smetanin 			return 1;
216e83d5887SAndrey Smetanin 		break;
217e83d5887SAndrey Smetanin 	}
218e83d5887SAndrey Smetanin 	case HV_X64_MSR_EOI:
219e83d5887SAndrey Smetanin 		return kvm_hv_vapic_msr_write(vcpu, APIC_EOI, data);
220e83d5887SAndrey Smetanin 	case HV_X64_MSR_ICR:
221e83d5887SAndrey Smetanin 		return kvm_hv_vapic_msr_write(vcpu, APIC_ICR, data);
222e83d5887SAndrey Smetanin 	case HV_X64_MSR_TPR:
223e83d5887SAndrey Smetanin 		return kvm_hv_vapic_msr_write(vcpu, APIC_TASKPRI, data);
224*9eec50b8SAndrey Smetanin 	case HV_X64_MSR_VP_RUNTIME:
225*9eec50b8SAndrey Smetanin 		if (!host)
226*9eec50b8SAndrey Smetanin 			return 1;
227*9eec50b8SAndrey Smetanin 		hv->runtime_offset = data - current_task_runtime_100ns();
228*9eec50b8SAndrey Smetanin 		break;
229e83d5887SAndrey Smetanin 	default:
230e83d5887SAndrey Smetanin 		vcpu_unimpl(vcpu, "Hyper-V uhandled wrmsr: 0x%x data 0x%llx\n",
231e83d5887SAndrey Smetanin 			    msr, data);
232e83d5887SAndrey Smetanin 		return 1;
233e83d5887SAndrey Smetanin 	}
234e83d5887SAndrey Smetanin 
235e83d5887SAndrey Smetanin 	return 0;
236e83d5887SAndrey Smetanin }
237e83d5887SAndrey Smetanin 
238e83d5887SAndrey Smetanin static int kvm_hv_get_msr_pw(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
239e83d5887SAndrey Smetanin {
240e83d5887SAndrey Smetanin 	u64 data = 0;
241e83d5887SAndrey Smetanin 	struct kvm *kvm = vcpu->kvm;
242e83d5887SAndrey Smetanin 	struct kvm_hv *hv = &kvm->arch.hyperv;
243e83d5887SAndrey Smetanin 
244e83d5887SAndrey Smetanin 	switch (msr) {
245e83d5887SAndrey Smetanin 	case HV_X64_MSR_GUEST_OS_ID:
246e83d5887SAndrey Smetanin 		data = hv->hv_guest_os_id;
247e83d5887SAndrey Smetanin 		break;
248e83d5887SAndrey Smetanin 	case HV_X64_MSR_HYPERCALL:
249e83d5887SAndrey Smetanin 		data = hv->hv_hypercall;
250e83d5887SAndrey Smetanin 		break;
251e83d5887SAndrey Smetanin 	case HV_X64_MSR_TIME_REF_COUNT: {
252e83d5887SAndrey Smetanin 		data =
253e83d5887SAndrey Smetanin 		     div_u64(get_kernel_ns() + kvm->arch.kvmclock_offset, 100);
254e83d5887SAndrey Smetanin 		break;
255e83d5887SAndrey Smetanin 	}
256e83d5887SAndrey Smetanin 	case HV_X64_MSR_REFERENCE_TSC:
257e83d5887SAndrey Smetanin 		data = hv->hv_tsc_page;
258e83d5887SAndrey Smetanin 		break;
259e7d9513bSAndrey Smetanin 	case HV_X64_MSR_CRASH_P0 ... HV_X64_MSR_CRASH_P4:
260e7d9513bSAndrey Smetanin 		return kvm_hv_msr_get_crash_data(vcpu,
261e7d9513bSAndrey Smetanin 						 msr - HV_X64_MSR_CRASH_P0,
262e7d9513bSAndrey Smetanin 						 pdata);
263e7d9513bSAndrey Smetanin 	case HV_X64_MSR_CRASH_CTL:
264e7d9513bSAndrey Smetanin 		return kvm_hv_msr_get_crash_ctl(vcpu, pdata);
265e516cebbSAndrey Smetanin 	case HV_X64_MSR_RESET:
266e516cebbSAndrey Smetanin 		data = 0;
267e516cebbSAndrey Smetanin 		break;
268e83d5887SAndrey Smetanin 	default:
269e83d5887SAndrey Smetanin 		vcpu_unimpl(vcpu, "Hyper-V unhandled rdmsr: 0x%x\n", msr);
270e83d5887SAndrey Smetanin 		return 1;
271e83d5887SAndrey Smetanin 	}
272e83d5887SAndrey Smetanin 
273e83d5887SAndrey Smetanin 	*pdata = data;
274e83d5887SAndrey Smetanin 	return 0;
275e83d5887SAndrey Smetanin }
276e83d5887SAndrey Smetanin 
277e83d5887SAndrey Smetanin static int kvm_hv_get_msr(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
278e83d5887SAndrey Smetanin {
279e83d5887SAndrey Smetanin 	u64 data = 0;
280e83d5887SAndrey Smetanin 	struct kvm_vcpu_hv *hv = &vcpu->arch.hyperv;
281e83d5887SAndrey Smetanin 
282e83d5887SAndrey Smetanin 	switch (msr) {
283e83d5887SAndrey Smetanin 	case HV_X64_MSR_VP_INDEX: {
284e83d5887SAndrey Smetanin 		int r;
285e83d5887SAndrey Smetanin 		struct kvm_vcpu *v;
286e83d5887SAndrey Smetanin 
287e83d5887SAndrey Smetanin 		kvm_for_each_vcpu(r, v, vcpu->kvm) {
288e83d5887SAndrey Smetanin 			if (v == vcpu) {
289e83d5887SAndrey Smetanin 				data = r;
290e83d5887SAndrey Smetanin 				break;
291e83d5887SAndrey Smetanin 			}
292e83d5887SAndrey Smetanin 		}
293e83d5887SAndrey Smetanin 		break;
294e83d5887SAndrey Smetanin 	}
295e83d5887SAndrey Smetanin 	case HV_X64_MSR_EOI:
296e83d5887SAndrey Smetanin 		return kvm_hv_vapic_msr_read(vcpu, APIC_EOI, pdata);
297e83d5887SAndrey Smetanin 	case HV_X64_MSR_ICR:
298e83d5887SAndrey Smetanin 		return kvm_hv_vapic_msr_read(vcpu, APIC_ICR, pdata);
299e83d5887SAndrey Smetanin 	case HV_X64_MSR_TPR:
300e83d5887SAndrey Smetanin 		return kvm_hv_vapic_msr_read(vcpu, APIC_TASKPRI, pdata);
301e83d5887SAndrey Smetanin 	case HV_X64_MSR_APIC_ASSIST_PAGE:
302e83d5887SAndrey Smetanin 		data = hv->hv_vapic;
303e83d5887SAndrey Smetanin 		break;
304*9eec50b8SAndrey Smetanin 	case HV_X64_MSR_VP_RUNTIME:
305*9eec50b8SAndrey Smetanin 		data = current_task_runtime_100ns() + hv->runtime_offset;
306*9eec50b8SAndrey Smetanin 		break;
307e83d5887SAndrey Smetanin 	default:
308e83d5887SAndrey Smetanin 		vcpu_unimpl(vcpu, "Hyper-V unhandled rdmsr: 0x%x\n", msr);
309e83d5887SAndrey Smetanin 		return 1;
310e83d5887SAndrey Smetanin 	}
311e83d5887SAndrey Smetanin 	*pdata = data;
312e83d5887SAndrey Smetanin 	return 0;
313e83d5887SAndrey Smetanin }
314e83d5887SAndrey Smetanin 
315e7d9513bSAndrey Smetanin int kvm_hv_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data, bool host)
316e83d5887SAndrey Smetanin {
317e83d5887SAndrey Smetanin 	if (kvm_hv_msr_partition_wide(msr)) {
318e83d5887SAndrey Smetanin 		int r;
319e83d5887SAndrey Smetanin 
320e83d5887SAndrey Smetanin 		mutex_lock(&vcpu->kvm->lock);
321e7d9513bSAndrey Smetanin 		r = kvm_hv_set_msr_pw(vcpu, msr, data, host);
322e83d5887SAndrey Smetanin 		mutex_unlock(&vcpu->kvm->lock);
323e83d5887SAndrey Smetanin 		return r;
324e83d5887SAndrey Smetanin 	} else
325*9eec50b8SAndrey Smetanin 		return kvm_hv_set_msr(vcpu, msr, data, host);
326e83d5887SAndrey Smetanin }
327e83d5887SAndrey Smetanin 
328e83d5887SAndrey Smetanin int kvm_hv_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
329e83d5887SAndrey Smetanin {
330e83d5887SAndrey Smetanin 	if (kvm_hv_msr_partition_wide(msr)) {
331e83d5887SAndrey Smetanin 		int r;
332e83d5887SAndrey Smetanin 
333e83d5887SAndrey Smetanin 		mutex_lock(&vcpu->kvm->lock);
334e83d5887SAndrey Smetanin 		r = kvm_hv_get_msr_pw(vcpu, msr, pdata);
335e83d5887SAndrey Smetanin 		mutex_unlock(&vcpu->kvm->lock);
336e83d5887SAndrey Smetanin 		return r;
337e83d5887SAndrey Smetanin 	} else
338e83d5887SAndrey Smetanin 		return kvm_hv_get_msr(vcpu, msr, pdata);
339e83d5887SAndrey Smetanin }
340e83d5887SAndrey Smetanin 
341e83d5887SAndrey Smetanin bool kvm_hv_hypercall_enabled(struct kvm *kvm)
342e83d5887SAndrey Smetanin {
343e83d5887SAndrey Smetanin 	return kvm->arch.hyperv.hv_hypercall & HV_X64_MSR_HYPERCALL_ENABLE;
344e83d5887SAndrey Smetanin }
345e83d5887SAndrey Smetanin 
346e83d5887SAndrey Smetanin int kvm_hv_hypercall(struct kvm_vcpu *vcpu)
347e83d5887SAndrey Smetanin {
348e83d5887SAndrey Smetanin 	u64 param, ingpa, outgpa, ret;
349e83d5887SAndrey Smetanin 	uint16_t code, rep_idx, rep_cnt, res = HV_STATUS_SUCCESS, rep_done = 0;
350e83d5887SAndrey Smetanin 	bool fast, longmode;
351e83d5887SAndrey Smetanin 
352e83d5887SAndrey Smetanin 	/*
353e83d5887SAndrey Smetanin 	 * hypercall generates UD from non zero cpl and real mode
354e83d5887SAndrey Smetanin 	 * per HYPER-V spec
355e83d5887SAndrey Smetanin 	 */
356e83d5887SAndrey Smetanin 	if (kvm_x86_ops->get_cpl(vcpu) != 0 || !is_protmode(vcpu)) {
357e83d5887SAndrey Smetanin 		kvm_queue_exception(vcpu, UD_VECTOR);
358e83d5887SAndrey Smetanin 		return 0;
359e83d5887SAndrey Smetanin 	}
360e83d5887SAndrey Smetanin 
361e83d5887SAndrey Smetanin 	longmode = is_64_bit_mode(vcpu);
362e83d5887SAndrey Smetanin 
363e83d5887SAndrey Smetanin 	if (!longmode) {
364e83d5887SAndrey Smetanin 		param = ((u64)kvm_register_read(vcpu, VCPU_REGS_RDX) << 32) |
365e83d5887SAndrey Smetanin 			(kvm_register_read(vcpu, VCPU_REGS_RAX) & 0xffffffff);
366e83d5887SAndrey Smetanin 		ingpa = ((u64)kvm_register_read(vcpu, VCPU_REGS_RBX) << 32) |
367e83d5887SAndrey Smetanin 			(kvm_register_read(vcpu, VCPU_REGS_RCX) & 0xffffffff);
368e83d5887SAndrey Smetanin 		outgpa = ((u64)kvm_register_read(vcpu, VCPU_REGS_RDI) << 32) |
369e83d5887SAndrey Smetanin 			(kvm_register_read(vcpu, VCPU_REGS_RSI) & 0xffffffff);
370e83d5887SAndrey Smetanin 	}
371e83d5887SAndrey Smetanin #ifdef CONFIG_X86_64
372e83d5887SAndrey Smetanin 	else {
373e83d5887SAndrey Smetanin 		param = kvm_register_read(vcpu, VCPU_REGS_RCX);
374e83d5887SAndrey Smetanin 		ingpa = kvm_register_read(vcpu, VCPU_REGS_RDX);
375e83d5887SAndrey Smetanin 		outgpa = kvm_register_read(vcpu, VCPU_REGS_R8);
376e83d5887SAndrey Smetanin 	}
377e83d5887SAndrey Smetanin #endif
378e83d5887SAndrey Smetanin 
379e83d5887SAndrey Smetanin 	code = param & 0xffff;
380e83d5887SAndrey Smetanin 	fast = (param >> 16) & 0x1;
381e83d5887SAndrey Smetanin 	rep_cnt = (param >> 32) & 0xfff;
382e83d5887SAndrey Smetanin 	rep_idx = (param >> 48) & 0xfff;
383e83d5887SAndrey Smetanin 
384e83d5887SAndrey Smetanin 	trace_kvm_hv_hypercall(code, fast, rep_cnt, rep_idx, ingpa, outgpa);
385e83d5887SAndrey Smetanin 
386e83d5887SAndrey Smetanin 	switch (code) {
387e83d5887SAndrey Smetanin 	case HV_X64_HV_NOTIFY_LONG_SPIN_WAIT:
388e83d5887SAndrey Smetanin 		kvm_vcpu_on_spin(vcpu);
389e83d5887SAndrey Smetanin 		break;
390e83d5887SAndrey Smetanin 	default:
391e83d5887SAndrey Smetanin 		res = HV_STATUS_INVALID_HYPERCALL_CODE;
392e83d5887SAndrey Smetanin 		break;
393e83d5887SAndrey Smetanin 	}
394e83d5887SAndrey Smetanin 
395e83d5887SAndrey Smetanin 	ret = res | (((u64)rep_done & 0xfff) << 32);
396e83d5887SAndrey Smetanin 	if (longmode) {
397e83d5887SAndrey Smetanin 		kvm_register_write(vcpu, VCPU_REGS_RAX, ret);
398e83d5887SAndrey Smetanin 	} else {
399e83d5887SAndrey Smetanin 		kvm_register_write(vcpu, VCPU_REGS_RDX, ret >> 32);
400e83d5887SAndrey Smetanin 		kvm_register_write(vcpu, VCPU_REGS_RAX, ret & 0xffffffff);
401e83d5887SAndrey Smetanin 	}
402e83d5887SAndrey Smetanin 
403e83d5887SAndrey Smetanin 	return 1;
404e83d5887SAndrey Smetanin }
405