VirtualBox

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

Last change on this file since 51576 was 51563, checked in by vboxsync, 11 years ago

VMM/GIM: bits.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.5 KB
Line 
1/* $Id: GIMAllHv.cpp 51563 2014-06-06 06:09:36Z vboxsync $ */
2/** @file
3 * GIM - Guest Interface Manager, Microsoft Hyper-V, All Contexts.
4 */
5
6/*
7 * Copyright (C) 2014 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
31
32/**
33 * Handles the Hyper-V hypercall.
34 *
35 * @returns VBox status code.
36 * @param pVCpu Pointer to the VMCPU.
37 * @param pCtx Pointer to the guest-CPU context.
38 */
39VMM_INT_DECL(int) GIMHvHypercall(PVMCPU pVCpu, PCPUMCTX pCtx)
40{
41 return VINF_SUCCESS;
42}
43
44
45/**
46 * Returns whether the guest has configured and enabled the use of Hyper-V's
47 * paravirtualized TSC.
48 *
49 * @returns true if paravirt. TSC is enabled, false otherwise.
50 * @param pVM Pointer to the VM.
51 */
52VMM_INT_DECL(bool) GIMHvIsParavirtTscEnabled(PVM pVM)
53{
54 return MSR_GIM_HV_REF_TSC_IS_ENABLED(pVM->gim.s.u.Hv.u64TscPageMsr);
55}
56
57
58/**
59 * Updates Hyper-V's reference TSC page.
60 *
61 * @returns VBox status code.
62 * @param pVM Pointer to the VM.
63 * @param u64Offset The computed TSC offset.
64 * @thread EMT(pVCpu)
65 */
66VMM_INT_DECL(int) GIMHvUpdateParavirtTsc(PVM pVM, uint64_t u64Offset)
67{
68 Assert(GIMIsEnabled(pVM));
69 bool fHvTscEnabled = MSR_GIM_HV_REF_TSC_IS_ENABLED(pVM->gim.s.u.Hv.u64TscPageMsr);
70 if (!fHvTscEnabled)
71 return VERR_GIM_PVTSC_NOT_ENABLED;
72
73 PGIMHV pHv = &pVM->gim.s.u.Hv;
74 PGIMMMIO2REGION pRegion = &pHv->aMmio2Regions[GIM_HV_HYPERCALL_PAGE_REGION_IDX];
75 PGIMHVREFTSC pRefTsc = (PGIMHVREFTSC)pRegion->CTX_SUFF(pvPage);
76 Assert(pRefTsc);
77
78 /** @todo Protect this with a spinlock! */
79 pRefTsc->u64TscScale = UINT64_C(0x1000000000000000);
80 pRefTsc->u64TscOffset = u64Offset;
81 ASMAtomicIncU32(&pRefTsc->u32TscSequence);
82
83 return VINF_SUCCESS;
84}
85
86
87/**
88 * MSR read handler for Hyper-V.
89 *
90 * @returns VBox status code.
91 * @param pVCpu Pointer to the VMCPU.
92 * @param idMsr The MSR being read.
93 * @param pRange The range this MSR belongs to.
94 * @param puValue Where to store the MSR value read.
95 */
96VMM_INT_DECL(int) GIMHvReadMsr(PVMCPU pVCpu, uint32_t idMsr, PCCPUMMSRRANGE pRange, uint64_t *puValue)
97{
98 NOREF(pRange);
99 PVM pVM = pVCpu->CTX_SUFF(pVM);
100 PGIMHV pHv = &pVM->gim.s.u.Hv;
101
102 switch (idMsr)
103 {
104 case MSR_GIM_HV_TIME_REF_COUNT:
105 {
106 /* Hyper-V reports the time in 100ns units. */
107 uint64_t u64Tsc = TMCpuTickGet(pVCpu);
108 uint64_t u64TscHz = TMCpuTicksPerSecond(pVM);
109 uint64_t u64Tsc100Ns = u64TscHz / UINT64_C(10000000); /* 100 ns */
110 *puValue = (u64Tsc / u64Tsc100Ns);
111 return VINF_SUCCESS;
112 }
113
114 case MSR_GIM_HV_VP_INDEX:
115 *puValue = pVCpu->idCpu;
116 return VINF_SUCCESS;
117
118 case MSR_GIM_HV_GUEST_OS_ID:
119 *puValue = pHv->u64GuestOsIdMsr;
120 return VINF_SUCCESS;
121
122 case MSR_GIM_HV_HYPERCALL:
123 *puValue = pHv->u64HypercallMsr;
124 return VINF_SUCCESS;
125
126 case MSR_GIM_HV_REF_TSC:
127 *puValue = pHv->u64TscPageMsr;
128 return VINF_SUCCESS;
129
130 case MSR_GIM_HV_TSC_FREQ:
131 *puValue = TMCpuTicksPerSecond(pVM);
132 return VINF_SUCCESS;
133
134 case MSR_GIM_HV_APIC_FREQ:
135 /** @todo Fix this later! Get the information from DevApic. */
136 *puValue = UINT32_C(1000000000); /* TMCLOCK_FREQ_VIRTUAL */
137 return VINF_SUCCESS;
138
139 default:
140 break;
141 }
142
143 LogRel(("GIMHvReadMsr: Unknown/invalid RdMsr %#RX32 -> #GP(0)\n", idMsr));
144 return VERR_CPUM_RAISE_GP_0;
145}
146
147
148/**
149 * MSR write handler for Hyper-V.
150 *
151 * @returns VBox status code.
152 * @param pVCpu Pointer to the VMCPU.
153 * @param idMsr The MSR being written.
154 * @param pRange The range this MSR belongs to.
155 * @param uRawValue The raw value with the ignored bits not masked.
156 */
157VMM_INT_DECL(int) GIMHvWriteMsr(PVMCPU pVCpu, uint32_t idMsr, PCCPUMMSRRANGE pRange, uint64_t uRawValue)
158{
159 NOREF(pRange);
160 PVM pVM = pVCpu->CTX_SUFF(pVM);
161 PGIMHV pHv = &pVM->gim.s.u.Hv;
162
163 switch (idMsr)
164 {
165 case MSR_GIM_HV_GUEST_OS_ID:
166 {
167#ifndef IN_RING3
168 return VERR_EM_INTERPRETER;
169#else
170 /* Disable the hypercall-page if 0 is written to this MSR. */
171 if (!uRawValue)
172 {
173 GIMR3Mmio2Unmap(pVM, &pHv->aMmio2Regions[GIM_HV_HYPERCALL_PAGE_REGION_IDX]);
174 pHv->u64HypercallMsr &= ~MSR_GIM_HV_HYPERCALL_ENABLE_BIT;
175 Log4Func(("Disabled hypercalls\n"));
176 }
177 pHv->u64GuestOsIdMsr = uRawValue;
178 return VINF_SUCCESS;
179#endif /* !IN_RING3 */
180 }
181
182 case MSR_GIM_HV_HYPERCALL:
183 {
184#ifndef IN_RING3
185 return VERR_EM_INTERPRETER;
186#else /* IN_RING3 */
187 /* First, update all but the hypercall enable bit. */
188 pHv->u64HypercallMsr = (uRawValue & ~MSR_GIM_HV_HYPERCALL_ENABLE_BIT);
189
190 /* Hypercalls can only be enabled when the guest has set the Guest-OS Id Msr. */
191 bool fEnable = RT_BOOL(uRawValue & MSR_GIM_HV_HYPERCALL_ENABLE_BIT);
192 if ( fEnable
193 && !pHv->u64GuestOsIdMsr)
194 {
195 return VINF_SUCCESS;
196 }
197
198 PPDMDEVINSR3 pDevIns = pVM->gim.s.pDevInsR3;
199 PGIMMMIO2REGION pRegion = &pHv->aMmio2Regions[GIM_HV_HYPERCALL_PAGE_REGION_IDX];
200 AssertPtr(pDevIns);
201 AssertPtr(pRegion);
202
203 /*
204 * Is the guest disabling the hypercall-page? Allow it regardless of the Guest-OS Id Msr.
205 */
206 if (!fEnable)
207 {
208 GIMR3Mmio2Unmap(pVM, pRegion);
209 pHv->u64HypercallMsr = uRawValue;
210 Log4Func(("Disabled hypercalls\n"));
211 return VINF_SUCCESS;
212 }
213
214 /*
215 * Map the hypercall-page.
216 */
217 RTGCPHYS GCPhysHypercallPage = MSR_GIM_HV_HYPERCALL_GUEST_PFN(uRawValue) << PAGE_SHIFT;
218 int rc = GIMR3Mmio2Map(pVM, pRegion, GCPhysHypercallPage, "Hyper-V Hypercall-page");
219 if (RT_SUCCESS(rc))
220 {
221 /*
222 * Patch the hypercall-page.
223 */
224 if (HMIsEnabled(pVM))
225 {
226 size_t cbWritten = 0;
227 rc = HMPatchHypercall(pVM, pRegion->pvPageR3, PAGE_SIZE, &cbWritten);
228 if ( RT_SUCCESS(rc)
229 && cbWritten < PAGE_SIZE - 1)
230 {
231 uint8_t *pbLast = (uint8_t *)pRegion->pvPageR3 + cbWritten;
232 *pbLast = 0xc3; /* RET */
233
234 pHv->u64HypercallMsr = uRawValue;
235 LogRelFunc(("Enabled hypercalls at %#RGp\n", GCPhysHypercallPage));
236 LogRelFunc(("%.*Rhxd\n", cbWritten + 1, (uint8_t *)pRegion->pvPageR3));
237 return VINF_SUCCESS;
238 }
239
240 LogFunc(("MSR_GIM_HV_HYPERCALL: HMPatchHypercall failed. rc=%Rrc cbWritten=%u\n", rc, cbWritten));
241 }
242 else
243 {
244 /** @todo Handle raw-mode hypercall page patching. */
245 LogRelFunc(("MSR_GIM_HV_HYPERCALL: raw-mode not yet implemented!\n"));
246 }
247
248 GIMR3Mmio2Unmap(pVM, pRegion);
249 }
250 else
251 LogFunc(("MSR_GIM_HV_HYPERCALL: GIMR3Mmio2Map failed. rc=%Rrc -> #GP(0)\n", rc));
252
253 return VERR_CPUM_RAISE_GP_0;
254#endif /* !IN_RING3 */
255 }
256
257 case MSR_GIM_HV_REF_TSC:
258 {
259#ifndef IN_RING3
260 return VERR_EM_INTERPRETER;
261#else /* IN_RING3 */
262 /* First, update all but the TSC-page enable bit. */
263 pHv->u64TscPageMsr = (uRawValue & ~MSR_GIM_HV_REF_TSC_ENABLE_BIT);
264
265 PPDMDEVINSR3 pDevIns = pVM->gim.s.pDevInsR3;
266 PGIMMMIO2REGION pRegion = &pHv->aMmio2Regions[GIM_HV_REF_TSC_PAGE_REGION_IDX];
267 AssertPtr(pDevIns);
268 AssertPtr(pRegion);
269
270 /*
271 * Is the guest disabling the TSC-page?
272 */
273 bool fEnable = RT_BOOL(uRawValue & MSR_GIM_HV_REF_TSC_ENABLE_BIT);
274 if (!fEnable)
275 {
276 GIMR3Mmio2Unmap(pVM, pRegion);
277 Log4Func(("Disabled TSC-page\n"));
278 return VINF_SUCCESS;
279 }
280
281 /*
282 * Map the TSC-page.
283 */
284 RTGCPHYS GCPhysTscPage = MSR_GIM_HV_REF_TSC_GUEST_PFN(uRawValue) << PAGE_SHIFT;
285 int rc = GIMR3Mmio2Map(pVM, pRegion, GCPhysTscPage, "Hyper-V TSC-page");
286 if (RT_SUCCESS(rc))
287 {
288 pHv->u64TscPageMsr = uRawValue;
289 Log4Func(("MSR_GIM_HV_REF_TSC: Enabled Hyper-V TSC page at %#RGp\n", GCPhysTscPage));
290 return VINF_SUCCESS;
291 }
292 else
293 LogFunc(("MSR_GIM_HV_REF_TSC: GIMR3Mmio2Map failed. rc=%Rrc -> #GP(0)\n", rc));
294
295 return VERR_CPUM_RAISE_GP_0;
296#endif /* !IN_RING3 */
297 }
298
299 case MSR_GIM_HV_TIME_REF_COUNT: /* Read-only MSRs. */
300 case MSR_GIM_HV_VP_INDEX:
301 case MSR_GIM_HV_TSC_FREQ:
302 case MSR_GIM_HV_APIC_FREQ:
303 LogFunc(("WrMsr on read-only MSR %#RX32 -> #GP(0)\n", idMsr));
304 return VERR_CPUM_RAISE_GP_0;
305
306 default:
307#ifdef IN_RING3
308 static uint32_t s_cTimes = 0;
309 if (s_cTimes++ < 20)
310 LogRel(("GIM: Unknown/invalid WrMsr (%#x,%#x`%08x) -> #GP(0)\n", idMsr, uRawValue & UINT64_C(0xffffffff00000000),
311 uRawValue & UINT64_C(0xffffffff)));
312#endif
313 LogFunc(("Unknown/invalid WrMsr (%#RX32,%#RX64) -> #GP(0)\n", idMsr, uRawValue));
314 break;
315 }
316
317 return VERR_CPUM_RAISE_GP_0;
318}
319
Note: See TracBrowser for help on using the repository browser.

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