VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMAll/GIMAllHv.cpp@ 55889

Last change on this file since 55889 was 54819, checked in by vboxsync, 10 years ago

VMM/GIM: Implemented KVM paravirt. provider.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.2 KB
Line 
1/* $Id: GIMAllHv.cpp 54819 2015-03-17 17:58:30Z vboxsync $ */
2/** @file
3 * GIM - Guest Interface Manager, Microsoft Hyper-V, All Contexts.
4 */
5
6/*
7 * Copyright (C) 2014-2015 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18/*******************************************************************************
19* Header Files *
20*******************************************************************************/
21#define LOG_GROUP LOG_GROUP_GIM
22#include "GIMHvInternal.h"
23#include "GIMInternal.h"
24
25#include <VBox/err.h>
26#include <VBox/vmm/hm.h>
27#include <VBox/vmm/tm.h>
28#include <VBox/vmm/vm.h>
29#include <VBox/vmm/pgm.h>
30#include <VBox/vmm/pdmdev.h>
31#include <VBox/vmm/pdmapi.h>
32
33#include <iprt/asm-amd64-x86.h>
34#include <iprt/spinlock.h>
35
36
37/**
38 * Handles the Hyper-V hypercall.
39 *
40 * @returns VBox status code.
41 * @param pVCpu Pointer to the VMCPU.
42 * @param pCtx Pointer to the guest-CPU context.
43 */
44VMM_INT_DECL(int) gimHvHypercall(PVMCPU pVCpu, PCPUMCTX pCtx)
45{
46 PVM pVM = pVCpu->CTX_SUFF(pVM);
47 if (!MSR_GIM_HV_HYPERCALL_IS_ENABLED(pVM->gim.s.u.Hv.u64HypercallMsr))
48 return VERR_GIM_HYPERCALLS_NOT_ENABLED;
49
50 /** @todo Handle hypercalls. Fail for now */
51 return VERR_GIM_IPE_3;
52}
53
54
55/**
56 * Returns whether the guest has configured and enabled the use of Hyper-V's
57 * hypercall interface.
58 *
59 * @returns true if hypercalls are enabled, false otherwise.
60 * @param pVCpu Pointer to the VMCPU.
61 */
62VMM_INT_DECL(bool) gimHvAreHypercallsEnabled(PVMCPU pVCpu)
63{
64 return MSR_GIM_HV_HYPERCALL_IS_ENABLED(pVCpu->CTX_SUFF(pVM)->gim.s.u.Hv.u64HypercallMsr);
65}
66
67
68/**
69 * Returns whether the guest has configured and enabled the use of Hyper-V's
70 * paravirtualized TSC.
71 *
72 * @returns true if paravirt. TSC is enabled, false otherwise.
73 * @param pVM Pointer to the VM.
74 */
75VMM_INT_DECL(bool) gimHvIsParavirtTscEnabled(PVM pVM)
76{
77 return MSR_GIM_HV_REF_TSC_IS_ENABLED(pVM->gim.s.u.Hv.u64TscPageMsr);
78}
79
80
81/**
82 * MSR read handler for Hyper-V.
83 *
84 * @returns Strict VBox status code like CPUMQueryGuestMsr().
85 * @retval VINF_CPUM_R3_MSR_READ
86 * @retval VERR_CPUM_RAISE_GP_0
87 *
88 * @param pVCpu Pointer to the VMCPU.
89 * @param idMsr The MSR being read.
90 * @param pRange The range this MSR belongs to.
91 * @param puValue Where to store the MSR value read.
92 */
93VMM_INT_DECL(VBOXSTRICTRC) gimHvReadMsr(PVMCPU pVCpu, uint32_t idMsr, PCCPUMMSRRANGE pRange, uint64_t *puValue)
94{
95 NOREF(pRange);
96 PVM pVM = pVCpu->CTX_SUFF(pVM);
97 PGIMHV pHv = &pVM->gim.s.u.Hv;
98
99 switch (idMsr)
100 {
101 case MSR_GIM_HV_TIME_REF_COUNT:
102 {
103 /* Hyper-V reports the time in 100 ns units (10 MHz). */
104 uint64_t u64Tsc = TMCpuTickGet(pVCpu);
105 uint64_t u64TscHz = TMCpuTicksPerSecond(pVM);
106 uint64_t u64Tsc100Ns = u64TscHz / UINT64_C(10000000); /* 100 ns */
107 *puValue = (u64Tsc / u64Tsc100Ns);
108 return VINF_SUCCESS;
109 }
110
111 case MSR_GIM_HV_VP_INDEX:
112 *puValue = pVCpu->idCpu;
113 return VINF_SUCCESS;
114
115 case MSR_GIM_HV_TPR:
116 PDMApicReadMSR(pVM, pVCpu->idCpu, 0x80, puValue);
117 return VINF_SUCCESS;
118
119 case MSR_GIM_HV_EOI:
120 PDMApicReadMSR(pVM, pVCpu->idCpu, 0x0B, puValue);
121 return VINF_SUCCESS;
122
123 case MSR_GIM_HV_ICR:
124 PDMApicReadMSR(pVM, pVCpu->idCpu, 0x30, puValue);
125 return VINF_SUCCESS;
126
127 case MSR_GIM_HV_GUEST_OS_ID:
128 *puValue = pHv->u64GuestOsIdMsr;
129 return VINF_SUCCESS;
130
131 case MSR_GIM_HV_HYPERCALL:
132 *puValue = pHv->u64HypercallMsr;
133 return VINF_SUCCESS;
134
135 case MSR_GIM_HV_REF_TSC:
136 *puValue = pHv->u64TscPageMsr;
137 return VINF_SUCCESS;
138
139 case MSR_GIM_HV_TSC_FREQ:
140 *puValue = TMCpuTicksPerSecond(pVM);
141 return VINF_SUCCESS;
142
143 case MSR_GIM_HV_APIC_FREQ:
144 {
145 int rc = PDMApicGetTimerFreq(pVM, puValue);
146 if (RT_FAILURE(rc))
147 return VERR_CPUM_RAISE_GP_0;
148 return VINF_SUCCESS;
149 }
150
151 case MSR_GIM_HV_RESET:
152 *puValue = 0;
153 return VINF_SUCCESS;
154
155 default:
156 {
157#ifdef IN_RING3
158 static uint32_t s_cTimes = 0;
159 if (s_cTimes++ < 20)
160 LogRel(("GIM: HyperV: Unknown/invalid RdMsr (%#x) -> #GP(0)\n", idMsr));
161#endif
162 LogFunc(("Unknown/invalid RdMsr (%#RX32) -> #GP(0)\n", idMsr));
163 break;
164 }
165 }
166
167 return VERR_CPUM_RAISE_GP_0;
168}
169
170
171/**
172 * MSR write handler for Hyper-V.
173 *
174 * @returns Strict VBox status code like CPUMSetGuestMsr().
175 * @retval VINF_CPUM_R3_MSR_WRITE
176 * @retval VERR_CPUM_RAISE_GP_0
177 *
178 * @param pVCpu Pointer to the VMCPU.
179 * @param idMsr The MSR being written.
180 * @param pRange The range this MSR belongs to.
181 * @param uRawValue The raw value with the ignored bits not masked.
182 */
183VMM_INT_DECL(VBOXSTRICTRC) gimHvWriteMsr(PVMCPU pVCpu, uint32_t idMsr, PCCPUMMSRRANGE pRange, uint64_t uRawValue)
184{
185 NOREF(pRange);
186 PVM pVM = pVCpu->CTX_SUFF(pVM);
187 PGIMHV pHv = &pVM->gim.s.u.Hv;
188
189 switch (idMsr)
190 {
191 case MSR_GIM_HV_TPR:
192 PDMApicWriteMSR(pVM, pVCpu->idCpu, 0x80, uRawValue);
193 return VINF_SUCCESS;
194
195 case MSR_GIM_HV_EOI:
196 PDMApicWriteMSR(pVM, pVCpu->idCpu, 0x0B, uRawValue);
197 return VINF_SUCCESS;
198
199 case MSR_GIM_HV_ICR:
200 PDMApicWriteMSR(pVM, pVCpu->idCpu, 0x30, uRawValue);
201 return VINF_SUCCESS;
202
203 case MSR_GIM_HV_GUEST_OS_ID:
204 {
205#ifndef IN_RING3
206 return VINF_CPUM_R3_MSR_WRITE;
207#else
208 /* Disable the hypercall-page if 0 is written to this MSR. */
209 if (!uRawValue)
210 {
211 gimR3HvDisableHypercallPage(pVM);
212 pHv->u64HypercallMsr &= ~MSR_GIM_HV_HYPERCALL_ENABLE_BIT;
213 }
214 pHv->u64GuestOsIdMsr = uRawValue;
215 return VINF_SUCCESS;
216#endif /* IN_RING3 */
217 }
218
219 case MSR_GIM_HV_HYPERCALL:
220 {
221#ifndef IN_RING3
222 return VINF_CPUM_R3_MSR_WRITE;
223#else /* IN_RING3 */
224 /*
225 * For now ignore writes to the hypercall MSR (i.e. keeps it disabled).
226 * This is required to boot FreeBSD 10.1 (with Hyper-V enabled ofc),
227 * see @bugref{7270} comment #116.
228 */
229 return VINF_SUCCESS;
230# if 0
231 /* First, update all but the hypercall enable bit. */
232 pHv->u64HypercallMsr = (uRawValue & ~MSR_GIM_HV_HYPERCALL_ENABLE_BIT);
233
234 /* Hypercalls can only be enabled when the guest has set the Guest-OS Id Msr. */
235 bool fEnable = RT_BOOL(uRawValue & MSR_GIM_HV_HYPERCALL_ENABLE_BIT);
236 if ( fEnable
237 && !pHv->u64GuestOsIdMsr)
238 {
239 return VINF_SUCCESS;
240 }
241
242 /* Is the guest disabling the hypercall-page? Allow it regardless of the Guest-OS Id Msr. */
243 if (!fEnable)
244 {
245 gimR3HvDisableHypercallPage(pVM);
246 pHv->u64HypercallMsr = uRawValue;
247 return VINF_SUCCESS;
248 }
249
250 /* Enable the hypercall-page. */
251 RTGCPHYS GCPhysHypercallPage = MSR_GIM_HV_HYPERCALL_GUEST_PFN(uRawValue) << PAGE_SHIFT;
252 int rc = gimR3HvEnableHypercallPage(pVM, GCPhysHypercallPage);
253 if (RT_SUCCESS(rc))
254 {
255 pHv->u64HypercallMsr = uRawValue;
256 return VINF_SUCCESS;
257 }
258
259 return VERR_CPUM_RAISE_GP_0;
260# endif
261#endif /* IN_RING3 */
262 }
263
264 case MSR_GIM_HV_REF_TSC:
265 {
266#ifndef IN_RING3
267 return VINF_CPUM_R3_MSR_WRITE;
268#else /* IN_RING3 */
269 /* First, update all but the TSC-page enable bit. */
270 pHv->u64TscPageMsr = (uRawValue & ~MSR_GIM_HV_REF_TSC_ENABLE_BIT);
271
272 /* Is the guest disabling the TSC-page? */
273 bool fEnable = RT_BOOL(uRawValue & MSR_GIM_HV_REF_TSC_ENABLE_BIT);
274 if (!fEnable)
275 {
276 gimR3HvDisableTscPage(pVM);
277 pHv->u64TscPageMsr = uRawValue;
278 return VINF_SUCCESS;
279 }
280
281 /* Enable the TSC-page. */
282 RTGCPHYS GCPhysTscPage = MSR_GIM_HV_REF_TSC_GUEST_PFN(uRawValue) << PAGE_SHIFT;
283 int rc = gimR3HvEnableTscPage(pVM, GCPhysTscPage, false /* fUseThisTscSequence */, 0 /* uTscSequence */);
284 if (RT_SUCCESS(rc))
285 {
286 pHv->u64TscPageMsr = uRawValue;
287 return VINF_SUCCESS;
288 }
289
290 return VERR_CPUM_RAISE_GP_0;
291#endif /* IN_RING3 */
292 }
293
294 case MSR_GIM_HV_RESET:
295 {
296#ifndef IN_RING3
297 return VINF_CPUM_R3_MSR_WRITE;
298#else
299 if (MSR_GIM_HV_RESET_IS_SET(uRawValue))
300 {
301 LogRel(("GIM: HyperV: Reset initiated through MSR.\n"));
302 int rc = PDMDevHlpVMReset(pVM->gim.s.pDevInsR3);
303 AssertRC(rc);
304 }
305 /* else: Ignore writes to other bits. */
306 return VINF_SUCCESS;
307#endif /* IN_RING3 */
308 }
309
310 case MSR_GIM_HV_TIME_REF_COUNT: /* Read-only MSRs. */
311 case MSR_GIM_HV_VP_INDEX:
312 case MSR_GIM_HV_TSC_FREQ:
313 case MSR_GIM_HV_APIC_FREQ:
314 LogFunc(("WrMsr on read-only MSR %#RX32 -> #GP(0)\n", idMsr));
315 return VERR_CPUM_RAISE_GP_0;
316
317 default:
318 {
319#ifdef IN_RING3
320 static uint32_t s_cTimes = 0;
321 if (s_cTimes++ < 20)
322 LogRel(("GIM: HyperV: Unknown/invalid WrMsr (%#x,%#x`%08x) -> #GP(0)\n", idMsr,
323 uRawValue & UINT64_C(0xffffffff00000000), uRawValue & UINT64_C(0xffffffff)));
324#endif
325 LogFunc(("Unknown/invalid WrMsr (%#RX32,%#RX64) -> #GP(0)\n", idMsr, uRawValue));
326 break;
327 }
328 }
329
330 return VERR_CPUM_RAISE_GP_0;
331}
332
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette