VirtualBox

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

Last change on this file since 52343 was 52006, checked in by vboxsync, 11 years ago

VMM: VT-x and AMD-V support for making GIM hypercalls.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.7 KB
Line 
1/* $Id: GIMAllHv.cpp 52006 2014-07-12 12:01:19Z 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#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 VBox status code.
85 * @param pVCpu Pointer to the VMCPU.
86 * @param idMsr The MSR being read.
87 * @param pRange The range this MSR belongs to.
88 * @param puValue Where to store the MSR value read.
89 */
90VMM_INT_DECL(int) GIMHvReadMsr(PVMCPU pVCpu, uint32_t idMsr, PCCPUMMSRRANGE pRange, uint64_t *puValue)
91{
92 NOREF(pRange);
93 PVM pVM = pVCpu->CTX_SUFF(pVM);
94 PGIMHV pHv = &pVM->gim.s.u.Hv;
95
96 switch (idMsr)
97 {
98 case MSR_GIM_HV_TIME_REF_COUNT:
99 {
100 /** @todo r=ramshankar: Shouldn't we add the TSC offset here? */
101 /* Hyper-V reports the time in 100 ns units (10 MHz). */
102 uint64_t u64Tsc = TMCpuTickGet(pVCpu);
103 uint64_t u64TscHz = TMCpuTicksPerSecond(pVM);
104 uint64_t u64Tsc100Ns = u64TscHz / UINT64_C(10000000); /* 100 ns */
105 *puValue = (u64Tsc / u64Tsc100Ns);
106 return VINF_SUCCESS;
107 }
108
109 case MSR_GIM_HV_VP_INDEX:
110 *puValue = pVCpu->idCpu;
111 return VINF_SUCCESS;
112
113 case MSR_GIM_HV_TPR:
114 PDMApicReadMSR(pVM, pVCpu->idCpu, 0x80, puValue);
115 return VINF_SUCCESS;
116
117 case MSR_GIM_HV_EOI:
118 PDMApicReadMSR(pVM, pVCpu->idCpu, 0x0B, puValue);
119 return VINF_SUCCESS;
120
121 case MSR_GIM_HV_ICR:
122 PDMApicReadMSR(pVM, pVCpu->idCpu, 0x30, puValue);
123 return VINF_SUCCESS;
124
125 case MSR_GIM_HV_GUEST_OS_ID:
126 *puValue = pHv->u64GuestOsIdMsr;
127 return VINF_SUCCESS;
128
129 case MSR_GIM_HV_HYPERCALL:
130 *puValue = pHv->u64HypercallMsr;
131 return VINF_SUCCESS;
132
133 case MSR_GIM_HV_REF_TSC:
134 *puValue = pHv->u64TscPageMsr;
135 return VINF_SUCCESS;
136
137 case MSR_GIM_HV_TSC_FREQ:
138 *puValue = TMCpuTicksPerSecond(pVM);
139 return VINF_SUCCESS;
140
141 case MSR_GIM_HV_APIC_FREQ:
142 /** @todo Fix this later! Get the information from DevApic. */
143 *puValue = UINT32_C(1000000000); /* TMCLOCK_FREQ_VIRTUAL */
144 return VINF_SUCCESS;
145
146 case MSR_GIM_HV_RESET:
147 *puValue = 0;
148 return VINF_SUCCESS;
149
150 default:
151#ifdef IN_RING3
152 static uint32_t s_cTimes = 0;
153 if (s_cTimes++ < 20)
154 LogRel(("GIM: HyperV: Unknown/invalid RdMsr (%#x) -> #GP(0)\n", idMsr));
155#endif
156 LogFunc(("Unknown/invalid RdMsr (%#RX32) -> #GP(0)\n", idMsr));
157 break;
158 }
159
160 return VERR_CPUM_RAISE_GP_0;
161}
162
163
164/**
165 * MSR write handler for Hyper-V.
166 *
167 * @returns VBox status code.
168 * @param pVCpu Pointer to the VMCPU.
169 * @param idMsr The MSR being written.
170 * @param pRange The range this MSR belongs to.
171 * @param uRawValue The raw value with the ignored bits not masked.
172 */
173VMM_INT_DECL(int) GIMHvWriteMsr(PVMCPU pVCpu, uint32_t idMsr, PCCPUMMSRRANGE pRange, uint64_t uRawValue)
174{
175 NOREF(pRange);
176 PVM pVM = pVCpu->CTX_SUFF(pVM);
177 PGIMHV pHv = &pVM->gim.s.u.Hv;
178
179 switch (idMsr)
180 {
181 case MSR_GIM_HV_TPR:
182 PDMApicWriteMSR(pVM, pVCpu->idCpu, 0x80, uRawValue);
183 return VINF_SUCCESS;
184
185 case MSR_GIM_HV_EOI:
186 PDMApicWriteMSR(pVM, pVCpu->idCpu, 0x0B, uRawValue);
187 return VINF_SUCCESS;
188
189 case MSR_GIM_HV_ICR:
190 PDMApicWriteMSR(pVM, pVCpu->idCpu, 0x30, uRawValue);
191 return VINF_SUCCESS;
192
193 case MSR_GIM_HV_GUEST_OS_ID:
194 {
195#ifndef IN_RING3
196 return VERR_EM_INTERPRETER;
197#else
198 /* Disable the hypercall-page if 0 is written to this MSR. */
199 if (!uRawValue)
200 {
201 GIMR3HvDisableHypercallPage(pVM);
202 pHv->u64HypercallMsr &= ~MSR_GIM_HV_HYPERCALL_ENABLE_BIT;
203 }
204 pHv->u64GuestOsIdMsr = uRawValue;
205 return VINF_SUCCESS;
206#endif /* !IN_RING3 */
207 }
208
209 case MSR_GIM_HV_HYPERCALL:
210 {
211#ifndef IN_RING3
212 return VERR_EM_INTERPRETER;
213#else /* IN_RING3 */
214 /* First, update all but the hypercall enable bit. */
215 pHv->u64HypercallMsr = (uRawValue & ~MSR_GIM_HV_HYPERCALL_ENABLE_BIT);
216
217 /* Hypercalls can only be enabled when the guest has set the Guest-OS Id Msr. */
218 bool fEnable = RT_BOOL(uRawValue & MSR_GIM_HV_HYPERCALL_ENABLE_BIT);
219 if ( fEnable
220 && !pHv->u64GuestOsIdMsr)
221 {
222 return VINF_SUCCESS;
223 }
224
225 /* Is the guest disabling the hypercall-page? Allow it regardless of the Guest-OS Id Msr. */
226 if (!fEnable)
227 {
228 GIMR3HvDisableHypercallPage(pVM);
229 pHv->u64HypercallMsr = uRawValue;
230 return VINF_SUCCESS;
231 }
232
233 /* Enable the hypercall-page. */
234 RTGCPHYS GCPhysHypercallPage = MSR_GIM_HV_HYPERCALL_GUEST_PFN(uRawValue) << PAGE_SHIFT;
235 int rc = GIMR3HvEnableHypercallPage(pVM, GCPhysHypercallPage);
236 if (RT_SUCCESS(rc))
237 {
238 pHv->u64HypercallMsr = uRawValue;
239 return VINF_SUCCESS;
240 }
241
242 return VERR_CPUM_RAISE_GP_0;
243#endif /* !IN_RING3 */
244 }
245
246 case MSR_GIM_HV_REF_TSC:
247 {
248#ifndef IN_RING3
249 return VERR_EM_INTERPRETER;
250#else /* IN_RING3 */
251 /* First, update all but the TSC-page enable bit. */
252 pHv->u64TscPageMsr = (uRawValue & ~MSR_GIM_HV_REF_TSC_ENABLE_BIT);
253
254 /* Is the guest disabling the TSC-page? */
255 bool fEnable = RT_BOOL(uRawValue & MSR_GIM_HV_REF_TSC_ENABLE_BIT);
256 if (!fEnable)
257 {
258 GIMR3HvDisableTscPage(pVM);
259 pHv->u64TscPageMsr = uRawValue;
260 return VINF_SUCCESS;
261 }
262
263 /* Enable the TSC-page. */
264 RTGCPHYS GCPhysTscPage = MSR_GIM_HV_REF_TSC_GUEST_PFN(uRawValue) << PAGE_SHIFT;
265 int rc = GIMR3HvEnableTscPage(pVM, GCPhysTscPage, false /* fUseThisTscSequence */, 0 /* uTscSequence */);
266 if (RT_SUCCESS(rc))
267 {
268 pHv->u64TscPageMsr = uRawValue;
269 return VINF_SUCCESS;
270 }
271
272 return VERR_CPUM_RAISE_GP_0;
273#endif /* !IN_RING3 */
274 }
275
276 case MSR_GIM_HV_RESET:
277 {
278#ifndef IN_RING3
279 return VERR_EM_INTERPRETER;
280#else
281 if (MSR_GIM_HV_RESET_IS_SET(uRawValue))
282 {
283 LogRel(("GIM: HyperV: Reset initiated through MSR.\n"));
284 int rc = PDMDevHlpVMReset(pVM->gim.s.pDevInsR3);
285 AssertRC(rc);
286 }
287 /* else: Ignore writes to other bits. */
288 return VINF_SUCCESS;
289#endif /* !IN_RING3 */
290 }
291
292 case MSR_GIM_HV_TIME_REF_COUNT: /* Read-only MSRs. */
293 case MSR_GIM_HV_VP_INDEX:
294 case MSR_GIM_HV_TSC_FREQ:
295 case MSR_GIM_HV_APIC_FREQ:
296 LogFunc(("WrMsr on read-only MSR %#RX32 -> #GP(0)\n", idMsr));
297 return VERR_CPUM_RAISE_GP_0;
298
299 default:
300#ifdef IN_RING3
301 static uint32_t s_cTimes = 0;
302 if (s_cTimes++ < 20)
303 LogRel(("GIM: HyperV: Unknown/invalid WrMsr (%#x,%#x`%08x) -> #GP(0)\n", idMsr, uRawValue & UINT64_C(0xffffffff00000000),
304 uRawValue & UINT64_C(0xffffffff)));
305#endif
306 LogFunc(("Unknown/invalid WrMsr (%#RX32,%#RX64) -> #GP(0)\n", idMsr, uRawValue));
307 break;
308 }
309
310 return VERR_CPUM_RAISE_GP_0;
311}
312
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