VirtualBox

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

Last change on this file since 56790 was 56790, checked in by vboxsync, 9 years ago

VMM/GIM: unused header.

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