VirtualBox

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

Last change on this file since 51981 was 51980, checked in by vboxsync, 11 years ago

VMM/GIM: Get system-reset MSR working, added EOI, TPR, ICR APIC MSR read/writes.

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