VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR3/GIMHv.cpp@ 72190

Last change on this file since 72190 was 72190, checked in by vboxsync, 7 years ago

VMM/GIM/HyperV: Implement extended hypercalls HvExtCallQueryCapabilities and HvExtCallGetBootZeroedMemory.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 84.5 KB
Line 
1/* $Id: GIMHv.cpp 72190 2018-05-10 15:19:33Z vboxsync $ */
2/** @file
3 * GIM - Guest Interface Manager, Hyper-V implementation.
4 */
5
6/*
7 * Copyright (C) 2014-2017 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/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_GIM
23#include <VBox/vmm/apic.h>
24#include <VBox/vmm/gim.h>
25#include <VBox/vmm/cpum.h>
26#include <VBox/vmm/mm.h>
27#include <VBox/vmm/ssm.h>
28#include <VBox/vmm/hm.h>
29#include <VBox/vmm/pdmapi.h>
30#include "GIMInternal.h"
31#include <VBox/vmm/vm.h>
32
33#include <VBox/version.h>
34
35#include <iprt/assert.h>
36#include <iprt/err.h>
37#include <iprt/string.h>
38#include <iprt/mem.h>
39#include <iprt/semaphore.h>
40#include <iprt/spinlock.h>
41#ifdef DEBUG_ramshankar
42# include <iprt/udp.h>
43#endif
44
45
46/*********************************************************************************************************************************
47* Defined Constants And Macros *
48*********************************************************************************************************************************/
49/**
50 * GIM Hyper-V saved-state version.
51 */
52#define GIM_HV_SAVED_STATE_VERSION UINT32_C(3)
53/** Saved states, prior to any synthetic interrupt controller support. */
54#define GIM_HV_SAVED_STATE_VERSION_PRE_SYNIC UINT32_C(2)
55/** Vanilla saved states, prior to any debug support. */
56#define GIM_HV_SAVED_STATE_VERSION_PRE_DEBUG UINT32_C(1)
57
58#ifdef VBOX_WITH_STATISTICS
59# define GIMHV_MSRRANGE(a_uFirst, a_uLast, a_szName) \
60 { (a_uFirst), (a_uLast), kCpumMsrRdFn_Gim, kCpumMsrWrFn_Gim, 0, 0, 0, 0, 0, a_szName, { 0 }, { 0 }, { 0 }, { 0 } }
61#else
62# define GIMHV_MSRRANGE(a_uFirst, a_uLast, a_szName) \
63 { (a_uFirst), (a_uLast), kCpumMsrRdFn_Gim, kCpumMsrWrFn_Gim, 0, 0, 0, 0, 0, a_szName }
64#endif
65
66
67/*********************************************************************************************************************************
68* Global Variables *
69*********************************************************************************************************************************/
70/**
71 * Array of MSR ranges supported by Hyper-V.
72 */
73static CPUMMSRRANGE const g_aMsrRanges_HyperV[] =
74{
75 GIMHV_MSRRANGE(MSR_GIM_HV_RANGE0_START, MSR_GIM_HV_RANGE0_END, "Hyper-V range 0"),
76 GIMHV_MSRRANGE(MSR_GIM_HV_RANGE1_START, MSR_GIM_HV_RANGE1_END, "Hyper-V range 1"),
77 GIMHV_MSRRANGE(MSR_GIM_HV_RANGE2_START, MSR_GIM_HV_RANGE2_END, "Hyper-V range 2"),
78 GIMHV_MSRRANGE(MSR_GIM_HV_RANGE3_START, MSR_GIM_HV_RANGE3_END, "Hyper-V range 3"),
79 GIMHV_MSRRANGE(MSR_GIM_HV_RANGE4_START, MSR_GIM_HV_RANGE4_END, "Hyper-V range 4"),
80 GIMHV_MSRRANGE(MSR_GIM_HV_RANGE5_START, MSR_GIM_HV_RANGE5_END, "Hyper-V range 5"),
81 GIMHV_MSRRANGE(MSR_GIM_HV_RANGE6_START, MSR_GIM_HV_RANGE6_END, "Hyper-V range 6"),
82 GIMHV_MSRRANGE(MSR_GIM_HV_RANGE7_START, MSR_GIM_HV_RANGE7_END, "Hyper-V range 7"),
83 GIMHV_MSRRANGE(MSR_GIM_HV_RANGE8_START, MSR_GIM_HV_RANGE8_END, "Hyper-V range 8"),
84 GIMHV_MSRRANGE(MSR_GIM_HV_RANGE9_START, MSR_GIM_HV_RANGE9_END, "Hyper-V range 9"),
85 GIMHV_MSRRANGE(MSR_GIM_HV_RANGE10_START, MSR_GIM_HV_RANGE10_END, "Hyper-V range 10"),
86 GIMHV_MSRRANGE(MSR_GIM_HV_RANGE11_START, MSR_GIM_HV_RANGE11_END, "Hyper-V range 11"),
87 GIMHV_MSRRANGE(MSR_GIM_HV_RANGE12_START, MSR_GIM_HV_RANGE12_END, "Hyper-V range 12")
88};
89#undef GIMHV_MSRRANGE
90
91/**
92 * DHCP OFFER packet response to the guest (client) over the Hyper-V debug
93 * transport.
94 *
95 * - MAC: Destination: broadcast.
96 * - MAC: Source: 00:00:00:00:01 (hypervisor). It's important that it's
97 * different from the client's MAC address which is all 0's.
98 * - IP: Source: 10.0.5.1 (hypervisor)
99 * - IP: Destination: broadcast.
100 * - IP: Checksum included.
101 * - BOOTP: Client IP address: 10.0.5.5.
102 * - BOOTP: Server IP address: 10.0.5.1.
103 * - DHCP options: Subnet mask, router, lease-time, DHCP server identifier.
104 * Options are kept to a minimum required for making Windows guests happy.
105 */
106#define GIMHV_DEBUGCLIENT_IPV4 RT_H2N_U32_C(0x0a000505) /* 10.0.5.5 */
107#define GIMHV_DEBUGSERVER_IPV4 RT_H2N_U32_C(0x0a000501) /* 10.0.5.1 */
108static const uint8_t g_abDhcpOffer[] =
109{
110 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x45, 0x10,
111 0x01, 0x28, 0x00, 0x00, 0x00, 0x00, 0x40, 0x11, 0x6a, 0xb5, 0x0a, 0x00, 0x05, 0x01, 0xff, 0xff,
112 0xff, 0xff, 0x00, 0x43, 0x00, 0x44, 0x01, 0x14, 0x00, 0x00, 0x02, 0x01, 0x06, 0x00, 0x00, 0x00,
113 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x05, 0x05, 0x00, 0x00,
114 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
115 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
116 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
117 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
118 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
119 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
120 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
121 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
122 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
123 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
124 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
125 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
126 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
127 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x82, 0x53, 0x63, 0x35, 0x01, 0x02, 0x01, 0x04, 0xff,
128 0xff, 0xff, 0x00, 0x03, 0x04, 0x0a, 0x00, 0x05, 0x01, 0x33, 0x04, 0xff, 0xff, 0xff, 0xff, 0x36,
129 0x04, 0x0a, 0x00, 0x05, 0x01, 0xff
130};
131
132/**
133 * DHCP ACK packet response to the guest (client) over the Hyper-V debug
134 * transport.
135 *
136 * - MAC: Destination: 00:00:00:00:00 (client).
137 * - IP: Destination: 10.0.5.5 (client).
138 * - Rest are mostly similar to the DHCP offer.
139 */
140static const uint8_t g_abDhcpAck[] =
141{
142 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x45, 0x10,
143 0x01, 0x28, 0x00, 0x00, 0x00, 0x00, 0x40, 0x11, 0x5b, 0xb0, 0x0a, 0x00, 0x05, 0x01, 0x0a, 0x00,
144 0x05, 0x05, 0x00, 0x43, 0x00, 0x44, 0x01, 0x14, 0x00, 0x00, 0x02, 0x01, 0x06, 0x00, 0x00, 0x00,
145 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x05, 0x05, 0x0a, 0x00, 0x05, 0x05, 0x00, 0x00,
146 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
147 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
148 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
149 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
150 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
151 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
152 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
153 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
154 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
155 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
156 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
157 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
158 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
159 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x82, 0x53, 0x63, 0x35, 0x01, 0x05, 0x01, 0x04, 0xff,
160 0xff, 0xff, 0x00, 0x03, 0x04, 0x0a, 0x00, 0x05, 0x01, 0x33, 0x04, 0xff, 0xff, 0xff, 0xff, 0x36,
161 0x04, 0x0a, 0x00, 0x05, 0x01, 0xff
162};
163
164/**
165 * ARP reply to the guest (client) over the Hyper-V debug transport.
166 *
167 * - MAC: Destination: 00:00:00:00:00 (client)
168 * - MAC: Source: 00:00:00:00:01 (hypervisor)
169 * - ARP: Reply: 10.0.5.1 is at Source MAC address.
170 */
171static const uint8_t g_abArpReply[] =
172{
173 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x06, 0x00, 0x01,
174 0x08, 0x00, 0x06, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0a, 0x00, 0x05, 0x01,
175 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x05, 0x05
176};
177
178
179/*********************************************************************************************************************************
180* Internal Functions *
181*********************************************************************************************************************************/
182static int gimR3HvInitHypercallSupport(PVM pVM);
183static void gimR3HvTermHypercallSupport(PVM pVM);
184static int gimR3HvInitDebugSupport(PVM pVM);
185static void gimR3HvTermDebugSupport(PVM pVM);
186static DECLCALLBACK(void) gimR3HvTimerCallback(PVM pVM, PTMTIMER pTimer, void *pvUser);
187
188/**
189 * Initializes the Hyper-V GIM provider.
190 *
191 * @returns VBox status code.
192 * @param pVM The cross context VM structure.
193 * @param pGimCfg The GIM CFGM node.
194 */
195VMMR3_INT_DECL(int) gimR3HvInit(PVM pVM, PCFGMNODE pGimCfg)
196{
197 AssertReturn(pVM, VERR_INVALID_PARAMETER);
198 AssertReturn(pVM->gim.s.enmProviderId == GIMPROVIDERID_HYPERV, VERR_INTERNAL_ERROR_5);
199
200 PGIMHV pHv = &pVM->gim.s.u.Hv;
201
202 /*
203 * Read configuration.
204 */
205 PCFGMNODE pCfgHv = CFGMR3GetChild(pGimCfg, "HyperV");
206 if (pCfgHv)
207 {
208 /*
209 * Validate the Hyper-V settings.
210 */
211 int rc2 = CFGMR3ValidateConfig(pCfgHv, "/HyperV/",
212 "VendorID"
213 "|VSInterface"
214 "|HypercallDebugInterface",
215 "" /* pszValidNodes */, "GIM/HyperV" /* pszWho */, 0 /* uInstance */);
216 if (RT_FAILURE(rc2))
217 return rc2;
218 }
219
220 /** @cfgm{/GIM/HyperV/VendorID, string, 'VBoxVBoxVBox'}
221 * The Hyper-V vendor signature, must be 12 characters. */
222 char szVendor[13];
223 int rc = CFGMR3QueryStringDef(pCfgHv, "VendorID", szVendor, sizeof(szVendor), "VBoxVBoxVBox");
224 AssertLogRelRCReturn(rc, rc);
225 AssertLogRelMsgReturn(strlen(szVendor) == 12,
226 ("The VendorID config value must be exactly 12 chars, '%s' isn't!\n", szVendor),
227 VERR_INVALID_PARAMETER);
228
229 LogRel(("GIM: HyperV: Reporting vendor as '%s'\n", szVendor));
230 /** @todo r=bird: GIM_HV_VENDOR_MICROSOFT is 12 char and the string is max
231 * 12+terminator, so the NCmp is a little bit misleading. */
232 if (!RTStrNCmp(szVendor, GIM_HV_VENDOR_MICROSOFT, sizeof(GIM_HV_VENDOR_MICROSOFT) - 1))
233 {
234 LogRel(("GIM: HyperV: Warning! Posing as the Microsoft vendor may alter guest behaviour!\n"));
235 pHv->fIsVendorMsHv = true;
236 }
237
238 /** @cfgm{/GIM/HyperV/VSInterface, bool, true}
239 * The Microsoft virtualization service interface (debugging). */
240 rc = CFGMR3QueryBoolDef(pCfgHv, "VSInterface", &pHv->fIsInterfaceVs, false);
241 AssertLogRelRCReturn(rc, rc);
242
243 /** @cfgm{/GIM/HyperV/HypercallDebugInterface, bool, false}
244 * Whether we specify the guest to use hypercalls for debugging rather than MSRs. */
245 rc = CFGMR3QueryBoolDef(pCfgHv, "HypercallDebugInterface", &pHv->fDbgHypercallInterface, false);
246 AssertLogRelRCReturn(rc, rc);
247
248 /*
249 * Determine interface capabilities based on the version.
250 */
251 if (!pVM->gim.s.u32Version)
252 {
253 /* Basic features. */
254 pHv->uBaseFeat = 0
255 //| GIM_HV_BASE_FEAT_VP_RUNTIME_MSR
256 | GIM_HV_BASE_FEAT_PART_TIME_REF_COUNT_MSR
257 //| GIM_HV_BASE_FEAT_BASIC_SYNIC_MSRS // Both required for synethetic timers
258 //| GIM_HV_BASE_FEAT_STIMER_MSRS // Both required for synethetic timers
259 | GIM_HV_BASE_FEAT_APIC_ACCESS_MSRS
260 | GIM_HV_BASE_FEAT_HYPERCALL_MSRS
261 | GIM_HV_BASE_FEAT_VP_ID_MSR
262 | GIM_HV_BASE_FEAT_VIRT_SYS_RESET_MSR
263 //| GIM_HV_BASE_FEAT_STAT_PAGES_MSR
264 | GIM_HV_BASE_FEAT_PART_REF_TSC_MSR
265 //| GIM_HV_BASE_FEAT_GUEST_IDLE_STATE_MSR
266 | GIM_HV_BASE_FEAT_TIMER_FREQ_MSRS
267 //| GIM_HV_BASE_FEAT_DEBUG_MSRS
268 ;
269
270 /* Miscellaneous features. */
271 pHv->uMiscFeat = 0
272 //| GIM_HV_MISC_FEAT_GUEST_DEBUGGING
273 //| GIM_HV_MISC_FEAT_XMM_HYPERCALL_INPUT
274 | GIM_HV_MISC_FEAT_TIMER_FREQ
275 | GIM_HV_MISC_FEAT_GUEST_CRASH_MSRS
276 //| GIM_HV_MISC_FEAT_DEBUG_MSRS
277 ;
278
279 /* Hypervisor recommendations to the guest. */
280 pHv->uHyperHints = GIM_HV_HINT_MSR_FOR_SYS_RESET
281 | GIM_HV_HINT_RELAX_TIME_CHECKS
282 | GIM_HV_HINT_X2APIC_MSRS
283 ;
284
285 /* Partition features. */
286 pHv->uPartFlags |= GIM_HV_PART_FLAGS_EXTENDED_HYPERCALLS;
287
288 /* Expose more if we're posing as Microsoft. We can, if needed, force MSR-based Hv
289 debugging by not exposing these bits while exposing the VS interface. The better
290 way is what we do currently, via the GIM_HV_DEBUG_OPTIONS_USE_HYPERCALLS bit. */
291 if (pHv->fIsVendorMsHv)
292 {
293 pHv->uMiscFeat |= GIM_HV_MISC_FEAT_GUEST_DEBUGGING
294 | GIM_HV_MISC_FEAT_DEBUG_MSRS;
295
296 pHv->uPartFlags |= GIM_HV_PART_FLAGS_DEBUGGING;
297 }
298 }
299
300 /*
301 * Populate the required fields in MMIO2 region records for registering.
302 */
303 AssertCompile(GIM_HV_PAGE_SIZE == PAGE_SIZE);
304 PGIMMMIO2REGION pRegion = &pHv->aMmio2Regions[GIM_HV_HYPERCALL_PAGE_REGION_IDX];
305 pRegion->iRegion = GIM_HV_HYPERCALL_PAGE_REGION_IDX;
306 pRegion->fRCMapping = false;
307 pRegion->cbRegion = PAGE_SIZE; /* Sanity checked in gimR3HvLoad(), gimR3HvEnableTscPage() & gimR3HvEnableHypercallPage() */
308 pRegion->GCPhysPage = NIL_RTGCPHYS;
309 RTStrCopy(pRegion->szDescription, sizeof(pRegion->szDescription), "Hyper-V hypercall page");
310
311 pRegion = &pHv->aMmio2Regions[GIM_HV_REF_TSC_PAGE_REGION_IDX];
312 pRegion->iRegion = GIM_HV_REF_TSC_PAGE_REGION_IDX;
313 pRegion->fRCMapping = false;
314 pRegion->cbRegion = PAGE_SIZE; /* Sanity checked in gimR3HvLoad(), gimR3HvEnableTscPage() & gimR3HvEnableHypercallPage() */
315 pRegion->GCPhysPage = NIL_RTGCPHYS;
316 RTStrCopy(pRegion->szDescription, sizeof(pRegion->szDescription), "Hyper-V TSC page");
317
318 /*
319 * Make sure the CPU ID bit are in accordance to the Hyper-V
320 * requirement and other paranoia checks.
321 * See "Requirements for implementing the Microsoft hypervisor interface" spec.
322 */
323 Assert(!(pHv->uPartFlags & ( GIM_HV_PART_FLAGS_CREATE_PART
324 | GIM_HV_PART_FLAGS_ACCESS_MEMORY_POOL
325 | GIM_HV_PART_FLAGS_ACCESS_PART_ID
326 | GIM_HV_PART_FLAGS_ADJUST_MSG_BUFFERS
327 | GIM_HV_PART_FLAGS_CREATE_PORT
328 | GIM_HV_PART_FLAGS_ACCESS_STATS
329 | GIM_HV_PART_FLAGS_CPU_MGMT
330 | GIM_HV_PART_FLAGS_CPU_PROFILER)));
331 Assert((pHv->uBaseFeat & (GIM_HV_BASE_FEAT_HYPERCALL_MSRS | GIM_HV_BASE_FEAT_VP_ID_MSR))
332 == (GIM_HV_BASE_FEAT_HYPERCALL_MSRS | GIM_HV_BASE_FEAT_VP_ID_MSR));
333#ifdef VBOX_STRICT
334 for (unsigned i = 0; i < RT_ELEMENTS(pHv->aMmio2Regions); i++)
335 {
336 PCGIMMMIO2REGION pCur = &pHv->aMmio2Regions[i];
337 Assert(!pCur->fRCMapping);
338 Assert(!pCur->fMapped);
339 Assert(pCur->GCPhysPage == NIL_RTGCPHYS);
340 }
341#endif
342
343 /*
344 * Expose HVP (Hypervisor Present) bit to the guest.
345 */
346 CPUMR3SetGuestCpuIdFeature(pVM, CPUMCPUIDFEATURE_HVP);
347
348 /*
349 * Modify the standard hypervisor leaves for Hyper-V.
350 */
351 CPUMCPUIDLEAF HyperLeaf;
352 RT_ZERO(HyperLeaf);
353 HyperLeaf.uLeaf = UINT32_C(0x40000000);
354 if ( pHv->fIsVendorMsHv
355 && pHv->fIsInterfaceVs)
356 HyperLeaf.uEax = UINT32_C(0x40000082); /* Since we expose 0x40000082 below for the Hyper-V PV-debugging case. */
357 else
358 HyperLeaf.uEax = UINT32_C(0x40000006); /* Minimum value for Hyper-V default is 0x40000005. */
359 /*
360 * Don't report vendor as 'Microsoft Hv'[1] by default, see @bugref{7270#c152}.
361 * [1]: ebx=0x7263694d ('rciM') ecx=0x666f736f ('foso') edx=0x76482074 ('vH t')
362 */
363 {
364 uint32_t uVendorEbx;
365 uint32_t uVendorEcx;
366 uint32_t uVendorEdx;
367 uVendorEbx = ((uint32_t)szVendor[ 3]) << 24 | ((uint32_t)szVendor[ 2]) << 16 | ((uint32_t)szVendor[1]) << 8
368 | (uint32_t)szVendor[ 0];
369 uVendorEcx = ((uint32_t)szVendor[ 7]) << 24 | ((uint32_t)szVendor[ 6]) << 16 | ((uint32_t)szVendor[5]) << 8
370 | (uint32_t)szVendor[ 4];
371 uVendorEdx = ((uint32_t)szVendor[11]) << 24 | ((uint32_t)szVendor[10]) << 16 | ((uint32_t)szVendor[9]) << 8
372 | (uint32_t)szVendor[ 8];
373 HyperLeaf.uEbx = uVendorEbx;
374 HyperLeaf.uEcx = uVendorEcx;
375 HyperLeaf.uEdx = uVendorEdx;
376 }
377 rc = CPUMR3CpuIdInsert(pVM, &HyperLeaf);
378 AssertLogRelRCReturn(rc, rc);
379
380 HyperLeaf.uLeaf = UINT32_C(0x40000001);
381 HyperLeaf.uEax = 0x31237648; /* 'Hv#1' */
382 HyperLeaf.uEbx = 0; /* Reserved */
383 HyperLeaf.uEcx = 0; /* Reserved */
384 HyperLeaf.uEdx = 0; /* Reserved */
385 rc = CPUMR3CpuIdInsert(pVM, &HyperLeaf);
386 AssertLogRelRCReturn(rc, rc);
387
388 /*
389 * Add Hyper-V specific leaves.
390 */
391 HyperLeaf.uLeaf = UINT32_C(0x40000002); /* MBZ until MSR_GIM_HV_GUEST_OS_ID is set by the guest. */
392 HyperLeaf.uEax = 0;
393 HyperLeaf.uEbx = 0;
394 HyperLeaf.uEcx = 0;
395 HyperLeaf.uEdx = 0;
396 rc = CPUMR3CpuIdInsert(pVM, &HyperLeaf);
397 AssertLogRelRCReturn(rc, rc);
398
399 HyperLeaf.uLeaf = UINT32_C(0x40000003);
400 HyperLeaf.uEax = pHv->uBaseFeat;
401 HyperLeaf.uEbx = pHv->uPartFlags;
402 HyperLeaf.uEcx = pHv->uPowMgmtFeat;
403 HyperLeaf.uEdx = pHv->uMiscFeat;
404 rc = CPUMR3CpuIdInsert(pVM, &HyperLeaf);
405 AssertLogRelRCReturn(rc, rc);
406
407 HyperLeaf.uLeaf = UINT32_C(0x40000004);
408 HyperLeaf.uEax = pHv->uHyperHints;
409 HyperLeaf.uEbx = 0xffffffff;
410 HyperLeaf.uEcx = 0;
411 HyperLeaf.uEdx = 0;
412 rc = CPUMR3CpuIdInsert(pVM, &HyperLeaf);
413 AssertLogRelRCReturn(rc, rc);
414
415 RT_ZERO(HyperLeaf);
416 HyperLeaf.uLeaf = UINT32_C(0x40000005);
417 rc = CPUMR3CpuIdInsert(pVM, &HyperLeaf);
418 AssertLogRelRCReturn(rc, rc);
419
420 /* Leaf 0x40000006 is inserted in gimR3HvInitCompleted(). */
421
422 if ( pHv->fIsVendorMsHv
423 && pHv->fIsInterfaceVs)
424 {
425 HyperLeaf.uLeaf = UINT32_C(0x40000080);
426 HyperLeaf.uEax = 0;
427 HyperLeaf.uEbx = 0x7263694d; /* 'rciM' */
428 HyperLeaf.uEcx = 0x666f736f; /* 'foso'*/
429 HyperLeaf.uEdx = 0x53562074; /* 'SV t' */
430 rc = CPUMR3CpuIdInsert(pVM, &HyperLeaf);
431 AssertLogRelRCReturn(rc, rc);
432
433 HyperLeaf.uLeaf = UINT32_C(0x40000081);
434 HyperLeaf.uEax = 0x31235356; /* '1#SV' */
435 HyperLeaf.uEbx = 0;
436 HyperLeaf.uEcx = 0;
437 HyperLeaf.uEdx = 0;
438 rc = CPUMR3CpuIdInsert(pVM, &HyperLeaf);
439 AssertLogRelRCReturn(rc, rc);
440
441 HyperLeaf.uLeaf = UINT32_C(0x40000082);
442 HyperLeaf.uEax = RT_BIT_32(1);
443 HyperLeaf.uEbx = 0;
444 HyperLeaf.uEcx = 0;
445 HyperLeaf.uEdx = 0;
446 rc = CPUMR3CpuIdInsert(pVM, &HyperLeaf);
447 AssertLogRelRCReturn(rc, rc);
448 }
449
450 /*
451 * Insert all MSR ranges of Hyper-V.
452 */
453 for (unsigned i = 0; i < RT_ELEMENTS(g_aMsrRanges_HyperV); i++)
454 {
455 int rc2 = CPUMR3MsrRangesInsert(pVM, &g_aMsrRanges_HyperV[i]);
456 AssertLogRelRCReturn(rc2, rc2);
457 }
458
459 /*
460 * Setup non-zero MSRs.
461 */
462 if (pHv->uMiscFeat & GIM_HV_MISC_FEAT_GUEST_CRASH_MSRS)
463 pHv->uCrashCtlMsr = MSR_GIM_HV_CRASH_CTL_NOTIFY;
464 for (VMCPUID i = 0; i < pVM->cCpus; i++)
465 {
466 PGIMHVCPU pHvCpu = &pVM->aCpus[i].gim.s.u.HvCpu;
467 for (uint8_t idxSintMsr = 0; idxSintMsr < RT_ELEMENTS(pHvCpu->auSintMsrs); idxSintMsr++)
468 pHvCpu->auSintMsrs[idxSintMsr] = MSR_GIM_HV_SINT_MASKED;
469 }
470
471 /*
472 * Setup hypercall support.
473 */
474 rc = gimR3HvInitHypercallSupport(pVM);
475 AssertLogRelRCReturn(rc, rc);
476
477 /*
478 * Setup debug support.
479 */
480 rc = gimR3HvInitDebugSupport(pVM);
481 AssertLogRelRCReturn(rc, rc);
482
483 /*
484 * Setup up the per-VCPU synthetic timers.
485 */
486 if ( (pHv->uBaseFeat & GIM_HV_BASE_FEAT_STIMER_MSRS)
487 || (pHv->uBaseFeat & GIM_HV_BASE_FEAT_BASIC_SYNIC_MSRS))
488 {
489 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
490 {
491 PVMCPU pVCpu = &pVM->aCpus[idCpu];
492 PGIMHVCPU pHvCpu = &pVCpu->gim.s.u.HvCpu;
493
494 for (uint8_t idxStimer = 0; idxStimer < RT_ELEMENTS(pHvCpu->aStimers); idxStimer++)
495 {
496 PGIMHVSTIMER pHvStimer = &pHvCpu->aStimers[idxStimer];
497
498 /* Associate the synthetic timer with its corresponding VCPU. */
499 pHvStimer->idCpu = pVCpu->idCpu;
500 pHvStimer->idxStimer = idxStimer;
501
502 /* Create the timer and associate the context pointers. */
503 RTStrPrintf(&pHvStimer->szTimerDesc[0], sizeof(pHvStimer->szTimerDesc), "Hyper-V[%u] Timer%u", pVCpu->idCpu,
504 idxStimer);
505 rc = TMR3TimerCreateInternal(pVM, TMCLOCK_VIRTUAL_SYNC, gimR3HvTimerCallback, pHvStimer /* pvUser */,
506 pHvStimer->szTimerDesc, &pHvStimer->pTimerR3);
507 AssertLogRelRCReturn(rc, rc);
508 pHvStimer->pTimerR0 = TMTimerR0Ptr(pHvStimer->pTimerR3);
509 pHvStimer->pTimerRC = TMTimerRCPtr(pHvStimer->pTimerR3);
510 }
511 }
512 }
513
514 /*
515 * Register statistics.
516 */
517 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
518 {
519 PVMCPU pVCpu = &pVM->aCpus[idCpu];
520 PGIMHVCPU pHvCpu = &pVCpu->gim.s.u.HvCpu;
521
522 for (size_t idxStimer = 0; idxStimer < RT_ELEMENTS(pHvCpu->aStatStimerFired); idxStimer++)
523 {
524 int rc2 = STAMR3RegisterF(pVM, &pHvCpu->aStatStimerFired[idxStimer], STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS,
525 STAMUNIT_OCCURENCES, "Number of times the synthetic timer fired.",
526 "/GIM/HyperV/%u/Stimer%u_Fired", idCpu, idxStimer);
527 AssertLogRelRCReturn(rc2, rc2);
528 }
529 }
530
531 return VINF_SUCCESS;
532}
533
534
535/**
536 * Initializes remaining bits of the Hyper-V provider.
537 *
538 * This is called after initializing HM and almost all other VMM components.
539 *
540 * @returns VBox status code.
541 * @param pVM The cross context VM structure.
542 */
543VMMR3_INT_DECL(int) gimR3HvInitCompleted(PVM pVM)
544{
545 PGIMHV pHv = &pVM->gim.s.u.Hv;
546 pHv->cTscTicksPerSecond = TMCpuTicksPerSecond(pVM);
547
548 /*
549 * Determine interface capabilities based on the version.
550 */
551 if (!pVM->gim.s.u32Version)
552 {
553 /* Hypervisor capabilities; features used by the hypervisor. */
554 pHv->uHyperCaps = HMIsNestedPagingActive(pVM) ? GIM_HV_HOST_FEAT_NESTED_PAGING : 0;
555 pHv->uHyperCaps |= HMAreMsrBitmapsAvailable(pVM) ? GIM_HV_HOST_FEAT_MSR_BITMAP : 0;
556 }
557
558 CPUMCPUIDLEAF HyperLeaf;
559 RT_ZERO(HyperLeaf);
560 HyperLeaf.uLeaf = UINT32_C(0x40000006);
561 HyperLeaf.uEax = pHv->uHyperCaps;
562 HyperLeaf.uEbx = 0;
563 HyperLeaf.uEcx = 0;
564 HyperLeaf.uEdx = 0;
565 int rc = CPUMR3CpuIdInsert(pVM, &HyperLeaf);
566 AssertLogRelRCReturn(rc, rc);
567
568 /*
569 * Inform APIC whether Hyper-V compatibility mode is enabled or not.
570 * Do this here rather than on gimR3HvInit() as it gets called after APIC
571 * has finished inserting/removing the x2APIC MSR range.
572 */
573 if (pHv->uHyperHints & GIM_HV_HINT_X2APIC_MSRS)
574 APICR3HvSetCompatMode(pVM, true);
575
576 return rc;
577}
578
579
580/**
581 * Terminates the Hyper-V GIM provider.
582 *
583 * @returns VBox status code.
584 * @param pVM The cross context VM structure.
585 */
586VMMR3_INT_DECL(int) gimR3HvTerm(PVM pVM)
587{
588 gimR3HvReset(pVM);
589 gimR3HvTermHypercallSupport(pVM);
590 gimR3HvTermDebugSupport(pVM);
591
592 PCGIMHV pHv = &pVM->gim.s.u.Hv;
593 if ( (pHv->uBaseFeat & GIM_HV_BASE_FEAT_STIMER_MSRS)
594 || (pHv->uBaseFeat & GIM_HV_BASE_FEAT_BASIC_SYNIC_MSRS))
595 {
596 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
597 {
598 PGIMHVCPU pHvCpu = &pVM->aCpus[idCpu].gim.s.u.HvCpu;
599 for (uint8_t idxStimer = 0; idxStimer < RT_ELEMENTS(pHvCpu->aStimers); idxStimer++)
600 {
601 PGIMHVSTIMER pHvStimer = &pHvCpu->aStimers[idxStimer];
602 TMR3TimerDestroy(pHvStimer->pTimerR3);
603 }
604 }
605 }
606
607 return VINF_SUCCESS;
608}
609
610
611/**
612 * Applies relocations to data and code managed by this
613 * component. This function will be called at init and
614 * whenever the VMM need to relocate it self inside the GC.
615 *
616 * @param pVM The cross context VM structure.
617 * @param offDelta Relocation delta relative to old location.
618 */
619VMMR3_INT_DECL(void) gimR3HvRelocate(PVM pVM, RTGCINTPTR offDelta)
620{
621 RT_NOREF1(offDelta);
622
623 PCGIMHV pHv = &pVM->gim.s.u.Hv;
624 if ( (pHv->uBaseFeat & GIM_HV_BASE_FEAT_STIMER_MSRS)
625 || (pHv->uBaseFeat & GIM_HV_BASE_FEAT_BASIC_SYNIC_MSRS))
626 {
627 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
628 {
629 PGIMHVCPU pHvCpu = &pVM->aCpus[idCpu].gim.s.u.HvCpu;
630 for (uint8_t idxStimer = 0; idxStimer < RT_ELEMENTS(pHvCpu->aStimers); idxStimer++)
631 {
632 PGIMHVSTIMER pHvStimer = &pHvCpu->aStimers[idxStimer];
633 pHvStimer->pTimerRC = TMTimerRCPtr(pHvStimer->pTimerR3);
634 }
635 }
636 }
637}
638
639
640/**
641 * This resets Hyper-V provider MSRs and unmaps whatever Hyper-V regions that
642 * the guest may have mapped.
643 *
644 * This is called when the VM is being reset.
645 *
646 * @param pVM The cross context VM structure.
647 *
648 * @thread EMT(0)
649 */
650VMMR3_INT_DECL(void) gimR3HvReset(PVM pVM)
651{
652 VM_ASSERT_EMT0(pVM);
653
654 /*
655 * Unmap MMIO2 pages that the guest may have setup.
656 */
657 LogRel(("GIM: HyperV: Resetting MMIO2 regions and MSRs\n"));
658 PGIMHV pHv = &pVM->gim.s.u.Hv;
659 for (unsigned i = 0; i < RT_ELEMENTS(pHv->aMmio2Regions); i++)
660 {
661 PGIMMMIO2REGION pRegion = &pHv->aMmio2Regions[i];
662#if 0
663 gimR3Mmio2Unmap(pVM, pRegion);
664#else
665 pRegion->fMapped = false;
666 pRegion->GCPhysPage = NIL_RTGCPHYS;
667#endif
668 }
669
670 /*
671 * Reset MSRs.
672 */
673 pHv->u64GuestOsIdMsr = 0;
674 pHv->u64HypercallMsr = 0;
675 pHv->u64TscPageMsr = 0;
676 pHv->uCrashP0Msr = 0;
677 pHv->uCrashP1Msr = 0;
678 pHv->uCrashP2Msr = 0;
679 pHv->uCrashP3Msr = 0;
680 pHv->uCrashP4Msr = 0;
681 pHv->uDbgStatusMsr = 0;
682 pHv->uDbgPendingBufferMsr = 0;
683 pHv->uDbgSendBufferMsr = 0;
684 pHv->uDbgRecvBufferMsr = 0;
685 for (VMCPUID i = 0; i < pVM->cCpus; i++)
686 {
687 PGIMHVCPU pHvCpu = &pVM->aCpus[i].gim.s.u.HvCpu;
688 pHvCpu->uSControlMsr = 0;
689 pHvCpu->uSimpMsr = 0;
690 pHvCpu->uSiefpMsr = 0;
691 pHvCpu->uApicAssistPageMsr = 0;
692
693 for (uint8_t idxSint = 0; idxSint < RT_ELEMENTS(pHvCpu->auSintMsrs); idxSint++)
694 pHvCpu->auSintMsrs[idxSint] = MSR_GIM_HV_SINT_MASKED;
695
696 for (uint8_t idxStimer = 0; idxStimer < RT_ELEMENTS(pHvCpu->aStimers); idxStimer++)
697 {
698 PGIMHVSTIMER pHvStimer = &pHvCpu->aStimers[idxStimer];
699 pHvStimer->uStimerConfigMsr = 0;
700 pHvStimer->uStimerCountMsr = 0;
701 }
702 }
703}
704
705
706/**
707 * Returns a pointer to the MMIO2 regions supported by Hyper-V.
708 *
709 * @returns Pointer to an array of MMIO2 regions.
710 * @param pVM The cross context VM structure.
711 * @param pcRegions Where to store the number of regions in the array.
712 */
713VMMR3_INT_DECL(PGIMMMIO2REGION) gimR3HvGetMmio2Regions(PVM pVM, uint32_t *pcRegions)
714{
715 Assert(GIMIsEnabled(pVM));
716 PGIMHV pHv = &pVM->gim.s.u.Hv;
717
718 *pcRegions = RT_ELEMENTS(pHv->aMmio2Regions);
719 Assert(*pcRegions <= UINT8_MAX); /* See PGMR3PhysMMIO2Register(). */
720 return pHv->aMmio2Regions;
721}
722
723
724/**
725 * Callback for when debug data is available over the debugger connection.
726 *
727 * @param pVM The cross context VM structure.
728 */
729static DECLCALLBACK(void) gimR3HvDebugBufAvail(PVM pVM)
730{
731 PGIMHV pHv = &pVM->gim.s.u.Hv;
732 RTGCPHYS GCPhysPendingBuffer = pHv->uDbgPendingBufferMsr;
733 if ( GCPhysPendingBuffer
734 && PGMPhysIsGCPhysNormal(pVM, GCPhysPendingBuffer))
735 {
736 uint8_t bPendingData = 1;
737 int rc = PGMPhysSimpleWriteGCPhys(pVM, GCPhysPendingBuffer, &bPendingData, sizeof(bPendingData));
738 if (RT_FAILURE(rc))
739 {
740 LogRelMax(5, ("GIM: HyperV: Failed to set pending debug receive buffer at %#RGp, rc=%Rrc\n", GCPhysPendingBuffer,
741 rc));
742 }
743 }
744}
745
746
747/**
748 * Callback for when debug data has been read from the debugger connection.
749 *
750 * This will be invoked before signalling read of the next debug buffer.
751 *
752 * @param pVM The cross context VM structure.
753 */
754static DECLCALLBACK(void) gimR3HvDebugBufReadCompleted(PVM pVM)
755{
756 PGIMHV pHv = &pVM->gim.s.u.Hv;
757 RTGCPHYS GCPhysPendingBuffer = pHv->uDbgPendingBufferMsr;
758 if ( GCPhysPendingBuffer
759 && PGMPhysIsGCPhysNormal(pVM, GCPhysPendingBuffer))
760 {
761 uint8_t bPendingData = 0;
762 int rc = PGMPhysSimpleWriteGCPhys(pVM, GCPhysPendingBuffer, &bPendingData, sizeof(bPendingData));
763 if (RT_FAILURE(rc))
764 {
765 LogRelMax(5, ("GIM: HyperV: Failed to clear pending debug receive buffer at %#RGp, rc=%Rrc\n", GCPhysPendingBuffer,
766 rc));
767 }
768 }
769}
770
771
772/**
773 * Get Hyper-V debug setup parameters.
774 *
775 * @returns VBox status code.
776 * @param pVM The cross context VM structure.
777 * @param pDbgSetup Where to store the debug setup details.
778 */
779VMMR3_INT_DECL(int) gimR3HvGetDebugSetup(PVM pVM, PGIMDEBUGSETUP pDbgSetup)
780{
781 Assert(pDbgSetup);
782 PGIMHV pHv = &pVM->gim.s.u.Hv;
783 if (pHv->fDbgEnabled)
784 {
785 pDbgSetup->pfnDbgRecvBufAvail = gimR3HvDebugBufAvail;
786 pDbgSetup->cbDbgRecvBuf = GIM_HV_PAGE_SIZE;
787 return VINF_SUCCESS;
788 }
789 return VERR_GIM_NO_DEBUG_CONNECTION;
790}
791
792
793/**
794 * Hyper-V state-save operation.
795 *
796 * @returns VBox status code.
797 * @param pVM The cross context VM structure.
798 * @param pSSM The saved state handle.
799 */
800VMMR3_INT_DECL(int) gimR3HvSave(PVM pVM, PSSMHANDLE pSSM)
801{
802 PCGIMHV pHv = &pVM->gim.s.u.Hv;
803
804 /*
805 * Save the Hyper-V SSM version.
806 */
807 SSMR3PutU32(pSSM, GIM_HV_SAVED_STATE_VERSION);
808
809 /*
810 * Save per-VM MSRs.
811 */
812 SSMR3PutU64(pSSM, pHv->u64GuestOsIdMsr);
813 SSMR3PutU64(pSSM, pHv->u64HypercallMsr);
814 SSMR3PutU64(pSSM, pHv->u64TscPageMsr);
815
816 /*
817 * Save Hyper-V features / capabilities.
818 */
819 SSMR3PutU32(pSSM, pHv->uBaseFeat);
820 SSMR3PutU32(pSSM, pHv->uPartFlags);
821 SSMR3PutU32(pSSM, pHv->uPowMgmtFeat);
822 SSMR3PutU32(pSSM, pHv->uMiscFeat);
823 SSMR3PutU32(pSSM, pHv->uHyperHints);
824 SSMR3PutU32(pSSM, pHv->uHyperCaps);
825
826 /*
827 * Save the Hypercall region.
828 */
829 PCGIMMMIO2REGION pRegion = &pHv->aMmio2Regions[GIM_HV_HYPERCALL_PAGE_REGION_IDX];
830 SSMR3PutU8(pSSM, pRegion->iRegion);
831 SSMR3PutBool(pSSM, pRegion->fRCMapping);
832 SSMR3PutU32(pSSM, pRegion->cbRegion);
833 SSMR3PutGCPhys(pSSM, pRegion->GCPhysPage);
834 SSMR3PutStrZ(pSSM, pRegion->szDescription);
835
836 /*
837 * Save the reference TSC region.
838 */
839 pRegion = &pHv->aMmio2Regions[GIM_HV_REF_TSC_PAGE_REGION_IDX];
840 SSMR3PutU8(pSSM, pRegion->iRegion);
841 SSMR3PutBool(pSSM, pRegion->fRCMapping);
842 SSMR3PutU32(pSSM, pRegion->cbRegion);
843 SSMR3PutGCPhys(pSSM, pRegion->GCPhysPage);
844 SSMR3PutStrZ(pSSM, pRegion->szDescription);
845 /* Save the TSC sequence so we can bump it on restore (as the CPU frequency/offset may change). */
846 uint32_t uTscSequence = 0;
847 if ( pRegion->fMapped
848 && MSR_GIM_HV_REF_TSC_IS_ENABLED(pHv->u64TscPageMsr))
849 {
850 PCGIMHVREFTSC pRefTsc = (PCGIMHVREFTSC)pRegion->pvPageR3;
851 uTscSequence = pRefTsc->u32TscSequence;
852 }
853 SSMR3PutU32(pSSM, uTscSequence);
854
855 /*
856 * Save debug support data.
857 */
858 SSMR3PutU64(pSSM, pHv->uDbgPendingBufferMsr);
859 SSMR3PutU64(pSSM, pHv->uDbgSendBufferMsr);
860 SSMR3PutU64(pSSM, pHv->uDbgRecvBufferMsr);
861 SSMR3PutU64(pSSM, pHv->uDbgStatusMsr);
862 SSMR3PutU32(pSSM, pHv->enmDbgReply);
863 SSMR3PutU32(pSSM, pHv->uDbgBootpXId);
864 SSMR3PutU32(pSSM, pHv->DbgGuestIp4Addr.u);
865
866 for (VMCPUID i = 0; i < pVM->cCpus; i++)
867 {
868 PGIMHVCPU pHvCpu = &pVM->aCpus[i].gim.s.u.HvCpu;
869 SSMR3PutU64(pSSM, pHvCpu->uSimpMsr);
870 for (size_t idxSintMsr = 0; idxSintMsr < RT_ELEMENTS(pHvCpu->auSintMsrs); idxSintMsr++)
871 SSMR3PutU64(pSSM, pHvCpu->auSintMsrs[idxSintMsr]);
872 }
873
874 return SSMR3PutU8(pSSM, UINT8_MAX);
875}
876
877
878/**
879 * Hyper-V state-load operation, final pass.
880 *
881 * @returns VBox status code.
882 * @param pVM The cross context VM structure.
883 * @param pSSM The saved state handle.
884 */
885VMMR3_INT_DECL(int) gimR3HvLoad(PVM pVM, PSSMHANDLE pSSM)
886{
887 /*
888 * Load the Hyper-V SSM version first.
889 */
890 uint32_t uHvSavedStateVersion;
891 int rc = SSMR3GetU32(pSSM, &uHvSavedStateVersion);
892 AssertRCReturn(rc, rc);
893 if ( uHvSavedStateVersion != GIM_HV_SAVED_STATE_VERSION
894 && uHvSavedStateVersion != GIM_HV_SAVED_STATE_VERSION_PRE_SYNIC
895 && uHvSavedStateVersion != GIM_HV_SAVED_STATE_VERSION_PRE_DEBUG)
896 return SSMR3SetLoadError(pSSM, VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION, RT_SRC_POS,
897 N_("Unsupported Hyper-V saved-state version %u (current %u)!"),
898 uHvSavedStateVersion, GIM_HV_SAVED_STATE_VERSION);
899
900 /*
901 * Update the TSC frequency from TM.
902 */
903 PGIMHV pHv = &pVM->gim.s.u.Hv;
904 pHv->cTscTicksPerSecond = TMCpuTicksPerSecond(pVM);
905
906 /*
907 * Load per-VM MSRs.
908 */
909 SSMR3GetU64(pSSM, &pHv->u64GuestOsIdMsr);
910 SSMR3GetU64(pSSM, &pHv->u64HypercallMsr);
911 SSMR3GetU64(pSSM, &pHv->u64TscPageMsr);
912
913 /*
914 * Load Hyper-V features / capabilities.
915 */
916 SSMR3GetU32(pSSM, &pHv->uBaseFeat);
917 SSMR3GetU32(pSSM, &pHv->uPartFlags);
918 SSMR3GetU32(pSSM, &pHv->uPowMgmtFeat);
919 SSMR3GetU32(pSSM, &pHv->uMiscFeat);
920 SSMR3GetU32(pSSM, &pHv->uHyperHints);
921 SSMR3GetU32(pSSM, &pHv->uHyperCaps);
922
923 /*
924 * Load and enable the Hypercall region.
925 */
926 PGIMMMIO2REGION pRegion = &pHv->aMmio2Regions[GIM_HV_HYPERCALL_PAGE_REGION_IDX];
927 SSMR3GetU8(pSSM, &pRegion->iRegion);
928 SSMR3GetBool(pSSM, &pRegion->fRCMapping);
929 SSMR3GetU32(pSSM, &pRegion->cbRegion);
930 SSMR3GetGCPhys(pSSM, &pRegion->GCPhysPage);
931 rc = SSMR3GetStrZ(pSSM, pRegion->szDescription, sizeof(pRegion->szDescription));
932 AssertRCReturn(rc, rc);
933
934 if (pRegion->cbRegion != PAGE_SIZE)
935 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Hypercall page region size %u invalid, expected %u"),
936 pRegion->cbRegion, PAGE_SIZE);
937
938 if (MSR_GIM_HV_HYPERCALL_PAGE_IS_ENABLED(pHv->u64HypercallMsr))
939 {
940 Assert(pRegion->GCPhysPage != NIL_RTGCPHYS);
941 if (RT_LIKELY(pRegion->fRegistered))
942 {
943 rc = gimR3HvEnableHypercallPage(pVM, pRegion->GCPhysPage);
944 if (RT_FAILURE(rc))
945 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Failed to enable the hypercall page. GCPhys=%#RGp rc=%Rrc"),
946 pRegion->GCPhysPage, rc);
947 }
948 else
949 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Hypercall MMIO2 region not registered. Missing GIM device?!"));
950 }
951
952 /*
953 * Load and enable the reference TSC region.
954 */
955 uint32_t uTscSequence;
956 pRegion = &pHv->aMmio2Regions[GIM_HV_REF_TSC_PAGE_REGION_IDX];
957 SSMR3GetU8(pSSM, &pRegion->iRegion);
958 SSMR3GetBool(pSSM, &pRegion->fRCMapping);
959 SSMR3GetU32(pSSM, &pRegion->cbRegion);
960 SSMR3GetGCPhys(pSSM, &pRegion->GCPhysPage);
961 SSMR3GetStrZ(pSSM, pRegion->szDescription, sizeof(pRegion->szDescription));
962 rc = SSMR3GetU32(pSSM, &uTscSequence);
963 AssertRCReturn(rc, rc);
964
965 if (pRegion->cbRegion != PAGE_SIZE)
966 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("TSC page region size %u invalid, expected %u"),
967 pRegion->cbRegion, PAGE_SIZE);
968
969 if (MSR_GIM_HV_REF_TSC_IS_ENABLED(pHv->u64TscPageMsr))
970 {
971 Assert(pRegion->GCPhysPage != NIL_RTGCPHYS);
972 if (pRegion->fRegistered)
973 {
974 rc = gimR3HvEnableTscPage(pVM, pRegion->GCPhysPage, true /* fUseThisTscSeq */, uTscSequence);
975 if (RT_FAILURE(rc))
976 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Failed to enable the TSC page. GCPhys=%#RGp rc=%Rrc"),
977 pRegion->GCPhysPage, rc);
978 }
979 else
980 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("TSC-page MMIO2 region not registered. Missing GIM device?!"));
981 }
982
983 /*
984 * Load the debug support data.
985 */
986 if (uHvSavedStateVersion > GIM_HV_SAVED_STATE_VERSION_PRE_DEBUG)
987 {
988 SSMR3GetU64(pSSM, &pHv->uDbgPendingBufferMsr);
989 SSMR3GetU64(pSSM, &pHv->uDbgSendBufferMsr);
990 SSMR3GetU64(pSSM, &pHv->uDbgRecvBufferMsr);
991 SSMR3GetU64(pSSM, &pHv->uDbgStatusMsr);
992 SSMR3GetU32(pSSM, (uint32_t *)&pHv->enmDbgReply);
993 SSMR3GetU32(pSSM, &pHv->uDbgBootpXId);
994 rc = SSMR3GetU32(pSSM, &pHv->DbgGuestIp4Addr.u);
995 AssertRCReturn(rc, rc);
996
997 for (VMCPUID i = 0; i < pVM->cCpus; i++)
998 {
999 PGIMHVCPU pHvCpu = &pVM->aCpus[i].gim.s.u.HvCpu;
1000 SSMR3GetU64(pSSM, &pHvCpu->uSimpMsr);
1001 if (uHvSavedStateVersion <= GIM_HV_SAVED_STATE_VERSION_PRE_SYNIC)
1002 SSMR3GetU64(pSSM, &pHvCpu->auSintMsrs[GIM_HV_VMBUS_MSG_SINT]);
1003 else
1004 {
1005 for (uint8_t idxSintMsr = 0; idxSintMsr < RT_ELEMENTS(pHvCpu->auSintMsrs); idxSintMsr++)
1006 SSMR3GetU64(pSSM, &pHvCpu->auSintMsrs[idxSintMsr]);
1007 }
1008 }
1009
1010 uint8_t bDelim;
1011 rc = SSMR3GetU8(pSSM, &bDelim);
1012 }
1013 else
1014 rc = VINF_SUCCESS;
1015
1016 return rc;
1017}
1018
1019
1020/**
1021 * Enables the Hyper-V APIC-assist page.
1022 *
1023 * @returns VBox status code.
1024 * @param pVCpu The cross context virtual CPU structure.
1025 * @param GCPhysApicAssistPage Where to map the APIC-assist page.
1026 */
1027VMMR3_INT_DECL(int) gimR3HvEnableApicAssistPage(PVMCPU pVCpu, RTGCPHYS GCPhysApicAssistPage)
1028{
1029 PVM pVM = pVCpu->CTX_SUFF(pVM);
1030 PPDMDEVINSR3 pDevIns = pVM->gim.s.pDevInsR3;
1031 AssertPtrReturn(pDevIns, VERR_GIM_DEVICE_NOT_REGISTERED);
1032
1033 /*
1034 * Map the APIC-assist-page at the specified address.
1035 */
1036 /** @todo this is buggy when large pages are used due to a PGM limitation, see
1037 * @bugref{7532}. Instead of the overlay style mapping, we just
1038 * rewrite guest memory directly. */
1039 size_t const cbApicAssistPage = PAGE_SIZE;
1040 void *pvApicAssist = RTMemAllocZ(cbApicAssistPage);
1041 if (RT_LIKELY(pvApicAssist))
1042 {
1043 int rc = PGMPhysSimpleWriteGCPhys(pVM, GCPhysApicAssistPage, pvApicAssist, cbApicAssistPage);
1044 if (RT_SUCCESS(rc))
1045 {
1046 /** @todo Inform APIC. */
1047 LogRel(("GIM%u: HyperV: Enabled APIC-assist page at %#RGp\n", pVCpu->idCpu, GCPhysApicAssistPage));
1048 }
1049 else
1050 {
1051 LogRelFunc(("GIM%u: HyperV: PGMPhysSimpleWriteGCPhys failed. rc=%Rrc\n", pVCpu->idCpu, rc));
1052 rc = VERR_GIM_OPERATION_FAILED;
1053 }
1054
1055 RTMemFree(pvApicAssist);
1056 return rc;
1057 }
1058
1059 LogRelFunc(("GIM%u: HyperV: Failed to alloc %u bytes\n", pVCpu->idCpu, cbApicAssistPage));
1060 return VERR_NO_MEMORY;
1061}
1062
1063
1064/**
1065 * Disables the Hyper-V APIC-assist page.
1066 *
1067 * @returns VBox status code.
1068 * @param pVCpu The cross context virtual CPU structure.
1069 */
1070VMMR3_INT_DECL(int) gimR3HvDisableApicAssistPage(PVMCPU pVCpu)
1071{
1072 LogRel(("GIM%u: HyperV: Disabled APIC-assist page\n", pVCpu->idCpu));
1073 /** @todo inform APIC */
1074 return VINF_SUCCESS;
1075}
1076
1077
1078/**
1079 * Hyper-V synthetic timer callback.
1080 *
1081 * @param pVM The cross context VM structure.
1082 * @param pTimer Pointer to timer.
1083 * @param pvUser Pointer to the synthetic timer.
1084 */
1085static DECLCALLBACK(void) gimR3HvTimerCallback(PVM pVM, PTMTIMER pTimer, void *pvUser)
1086{
1087 PGIMHVSTIMER pHvStimer = (PGIMHVSTIMER)pvUser;
1088 Assert(pHvStimer);
1089 Assert(TMTimerIsLockOwner(pTimer)); RT_NOREF(pTimer);
1090 Assert(pHvStimer->idCpu < pVM->cCpus);
1091
1092 PVMCPU pVCpu = &pVM->aCpus[pHvStimer->idCpu];
1093 PGIMHVCPU pHvCpu = &pVCpu->gim.s.u.HvCpu;
1094 Assert(pHvStimer->idxStimer < RT_ELEMENTS(pHvCpu->aStatStimerFired));
1095
1096 STAM_COUNTER_INC(&pHvCpu->aStatStimerFired[pHvStimer->idxStimer]);
1097
1098 uint64_t const uStimerConfig = pHvStimer->uStimerConfigMsr;
1099 uint16_t const idxSint = MSR_GIM_HV_STIMER_GET_SINTX(uStimerConfig);
1100 if (RT_LIKELY(idxSint < RT_ELEMENTS(pHvCpu->auSintMsrs)))
1101 {
1102 uint64_t const uSint = pHvCpu->auSintMsrs[idxSint];
1103 if (!MSR_GIM_HV_SINT_IS_MASKED(uSint))
1104 {
1105 uint8_t const uVector = MSR_GIM_HV_SINT_GET_VECTOR(uSint);
1106 bool const fAutoEoi = MSR_GIM_HV_SINT_IS_AUTOEOI(uSint);
1107 APICHvSendInterrupt(pVCpu, uVector, fAutoEoi, XAPICTRIGGERMODE_EDGE);
1108 }
1109 }
1110
1111 /* Re-arm the timer if it's periodic. */
1112 if (MSR_GIM_HV_STIMER_IS_PERIODIC(uStimerConfig))
1113 gimHvStartStimer(pVCpu, pHvStimer);
1114}
1115
1116
1117/**
1118 * Enables the Hyper-V SIEF page.
1119 *
1120 * @returns VBox status code.
1121 * @param pVCpu The cross context virtual CPU structure.
1122 * @param GCPhysSiefPage Where to map the SIEF page.
1123 */
1124VMMR3_INT_DECL(int) gimR3HvEnableSiefPage(PVMCPU pVCpu, RTGCPHYS GCPhysSiefPage)
1125{
1126 PVM pVM = pVCpu->CTX_SUFF(pVM);
1127 PPDMDEVINSR3 pDevIns = pVM->gim.s.pDevInsR3;
1128 AssertPtrReturn(pDevIns, VERR_GIM_DEVICE_NOT_REGISTERED);
1129
1130 /*
1131 * Map the SIEF page at the specified address.
1132 */
1133 /** @todo this is buggy when large pages are used due to a PGM limitation, see
1134 * @bugref{7532}. Instead of the overlay style mapping, we just
1135 * rewrite guest memory directly. */
1136 size_t const cbSiefPage = PAGE_SIZE;
1137 void *pvSiefPage = RTMemAllocZ(cbSiefPage);
1138 if (RT_LIKELY(pvSiefPage))
1139 {
1140 int rc = PGMPhysSimpleWriteGCPhys(pVM, GCPhysSiefPage, pvSiefPage, cbSiefPage);
1141 if (RT_SUCCESS(rc))
1142 {
1143 /** @todo SIEF setup. */
1144 LogRel(("GIM%u: HyperV: Enabled SIEF page at %#RGp\n", pVCpu->idCpu, GCPhysSiefPage));
1145 }
1146 else
1147 {
1148 LogRelFunc(("GIM%u: HyperV: PGMPhysSimpleWriteGCPhys failed. rc=%Rrc\n", pVCpu->idCpu, rc));
1149 rc = VERR_GIM_OPERATION_FAILED;
1150 }
1151
1152 RTMemFree(pvSiefPage);
1153 return rc;
1154 }
1155
1156 LogRelFunc(("GIM%u: HyperV: Failed to alloc %u bytes\n", pVCpu->idCpu, cbSiefPage));
1157 return VERR_NO_MEMORY;
1158}
1159
1160
1161/**
1162 * Disables the Hyper-V SIEF page.
1163 *
1164 * @returns VBox status code.
1165 * @param pVCpu The cross context virtual CPU structure.
1166 */
1167VMMR3_INT_DECL(int) gimR3HvDisableSiefPage(PVMCPU pVCpu)
1168{
1169 LogRel(("GIM%u: HyperV: Disabled APIC-assist page\n", pVCpu->idCpu));
1170 /** @todo SIEF teardown. */
1171 return VINF_SUCCESS;
1172}
1173
1174
1175/**
1176 * Enables the Hyper-V TSC page.
1177 *
1178 * @returns VBox status code.
1179 * @param pVM The cross context VM structure.
1180 * @param GCPhysTscPage Where to map the TSC page.
1181 * @param fUseThisTscSeq Whether to set the TSC sequence number to the one
1182 * specified in @a uTscSeq.
1183 * @param uTscSeq The TSC sequence value to use. Ignored if
1184 * @a fUseThisTscSeq is false.
1185 */
1186VMMR3_INT_DECL(int) gimR3HvEnableTscPage(PVM pVM, RTGCPHYS GCPhysTscPage, bool fUseThisTscSeq, uint32_t uTscSeq)
1187{
1188 PPDMDEVINSR3 pDevIns = pVM->gim.s.pDevInsR3;
1189 PGIMMMIO2REGION pRegion = &pVM->gim.s.u.Hv.aMmio2Regions[GIM_HV_REF_TSC_PAGE_REGION_IDX];
1190 AssertPtrReturn(pDevIns, VERR_GIM_DEVICE_NOT_REGISTERED);
1191
1192 int rc;
1193 if (pRegion->fMapped)
1194 {
1195 /*
1196 * Is it already enabled at the given guest-address?
1197 */
1198 if (pRegion->GCPhysPage == GCPhysTscPage)
1199 return VINF_SUCCESS;
1200
1201 /*
1202 * If it's mapped at a different address, unmap the previous address.
1203 */
1204 rc = gimR3HvDisableTscPage(pVM);
1205 AssertRC(rc);
1206 }
1207
1208 /*
1209 * Map the TSC-page at the specified address.
1210 */
1211 Assert(!pRegion->fMapped);
1212
1213 /** @todo this is buggy when large pages are used due to a PGM limitation, see
1214 * @bugref{7532}. Instead of the overlay style mapping, we just
1215 * rewrite guest memory directly. */
1216#if 0
1217 rc = gimR3Mmio2Map(pVM, pRegion, GCPhysTscPage);
1218 if (RT_SUCCESS(rc))
1219 {
1220 Assert(pRegion->GCPhysPage == GCPhysTscPage);
1221
1222 /*
1223 * Update the TSC scale. Windows guests expect a non-zero TSC sequence, otherwise
1224 * they fallback to using the reference count MSR which is not ideal in terms of VM-exits.
1225 *
1226 * Also, Hyper-V normalizes the time in 10 MHz, see:
1227 * http://technet.microsoft.com/it-it/sysinternals/dn553408%28v=vs.110%29
1228 */
1229 PGIMHVREFTSC pRefTsc = (PGIMHVREFTSC)pRegion->pvPageR3;
1230 Assert(pRefTsc);
1231
1232 PGIMHV pHv = &pVM->gim.s.u.Hv;
1233 uint64_t const u64TscKHz = pHv->cTscTicksPerSecond / UINT64_C(1000);
1234 uint32_t u32TscSeq = 1;
1235 if ( fUseThisTscSeq
1236 && uTscSeq < UINT32_C(0xfffffffe))
1237 u32TscSeq = uTscSeq + 1;
1238 pRefTsc->u32TscSequence = u32TscSeq;
1239 pRefTsc->u64TscScale = ((INT64_C(10000) << 32) / u64TscKHz) << 32;
1240 pRefTsc->i64TscOffset = 0;
1241
1242 LogRel(("GIM: HyperV: Enabled TSC page at %#RGp - u64TscScale=%#RX64 u64TscKHz=%#RX64 (%'RU64) Seq=%#RU32\n",
1243 GCPhysTscPage, pRefTsc->u64TscScale, u64TscKHz, u64TscKHz, pRefTsc->u32TscSequence));
1244
1245 TMR3CpuTickParavirtEnable(pVM);
1246 return VINF_SUCCESS;
1247 }
1248 else
1249 LogRelFunc(("gimR3Mmio2Map failed. rc=%Rrc\n", rc));
1250 return VERR_GIM_OPERATION_FAILED;
1251#else
1252 AssertReturn(pRegion->cbRegion == PAGE_SIZE, VERR_GIM_IPE_2);
1253 PGIMHVREFTSC pRefTsc = (PGIMHVREFTSC)RTMemAllocZ(PAGE_SIZE);
1254 if (RT_UNLIKELY(!pRefTsc))
1255 {
1256 LogRelFunc(("Failed to alloc %u bytes\n", PAGE_SIZE));
1257 return VERR_NO_MEMORY;
1258 }
1259
1260 PGIMHV pHv = &pVM->gim.s.u.Hv;
1261 uint64_t const u64TscKHz = pHv->cTscTicksPerSecond / UINT64_C(1000);
1262 uint32_t u32TscSeq = 1;
1263 if ( fUseThisTscSeq
1264 && uTscSeq < UINT32_C(0xfffffffe))
1265 u32TscSeq = uTscSeq + 1;
1266 pRefTsc->u32TscSequence = u32TscSeq;
1267 pRefTsc->u64TscScale = ((INT64_C(10000) << 32) / u64TscKHz) << 32;
1268 pRefTsc->i64TscOffset = 0;
1269
1270 rc = PGMPhysSimpleWriteGCPhys(pVM, GCPhysTscPage, pRefTsc, sizeof(*pRefTsc));
1271 if (RT_SUCCESS(rc))
1272 {
1273 LogRel(("GIM: HyperV: Enabled TSC page at %#RGp - u64TscScale=%#RX64 u64TscKHz=%#RX64 (%'RU64) Seq=%#RU32\n",
1274 GCPhysTscPage, pRefTsc->u64TscScale, u64TscKHz, u64TscKHz, pRefTsc->u32TscSequence));
1275
1276 pRegion->GCPhysPage = GCPhysTscPage;
1277 pRegion->fMapped = true;
1278 TMR3CpuTickParavirtEnable(pVM);
1279 }
1280 else
1281 {
1282 LogRelFunc(("GIM: HyperV: PGMPhysSimpleWriteGCPhys failed. rc=%Rrc\n", rc));
1283 rc = VERR_GIM_OPERATION_FAILED;
1284 }
1285 RTMemFree(pRefTsc);
1286 return rc;
1287#endif
1288}
1289
1290
1291/**
1292 * Enables the Hyper-V SIM page.
1293 *
1294 * @returns VBox status code.
1295 * @param pVCpu The cross context virtual CPU structure.
1296 * @param GCPhysSimPage Where to map the SIM page.
1297 */
1298VMMR3_INT_DECL(int) gimR3HvEnableSimPage(PVMCPU pVCpu, RTGCPHYS GCPhysSimPage)
1299{
1300 PVM pVM = pVCpu->CTX_SUFF(pVM);
1301 PPDMDEVINSR3 pDevIns = pVM->gim.s.pDevInsR3;
1302 AssertPtrReturn(pDevIns, VERR_GIM_DEVICE_NOT_REGISTERED);
1303
1304 /*
1305 * Map the SIMP page at the specified address.
1306 */
1307 /** @todo this is buggy when large pages are used due to a PGM limitation, see
1308 * @bugref{7532}. Instead of the overlay style mapping, we just
1309 * rewrite guest memory directly. */
1310 size_t const cbSimPage = PAGE_SIZE;
1311 void *pvSimPage = RTMemAllocZ(cbSimPage);
1312 if (RT_LIKELY(pvSimPage))
1313 {
1314 int rc = PGMPhysSimpleWriteGCPhys(pVM, GCPhysSimPage, pvSimPage, cbSimPage);
1315 if (RT_SUCCESS(rc))
1316 {
1317 /** @todo SIM setup. */
1318 LogRel(("GIM%u: HyperV: Enabled SIM page at %#RGp\n", pVCpu->idCpu, GCPhysSimPage));
1319 }
1320 else
1321 {
1322 LogRelFunc(("GIM%u: HyperV: PGMPhysSimpleWriteGCPhys failed. rc=%Rrc\n", pVCpu->idCpu, rc));
1323 rc = VERR_GIM_OPERATION_FAILED;
1324 }
1325
1326 RTMemFree(pvSimPage);
1327 return rc;
1328 }
1329
1330 LogRelFunc(("GIM%u: HyperV: Failed to alloc %u bytes\n", pVCpu->idCpu, cbSimPage));
1331 return VERR_NO_MEMORY;
1332}
1333
1334
1335/**
1336 * Disables the Hyper-V SIM page.
1337 *
1338 * @returns VBox status code.
1339 * @param pVCpu The cross context virtual CPU structure.
1340 */
1341VMMR3_INT_DECL(int) gimR3HvDisableSimPage(PVMCPU pVCpu)
1342{
1343 LogRel(("GIM%u: HyperV: Disabled SIM page\n", pVCpu->idCpu));
1344 /** @todo SIM teardown. */
1345 return VINF_SUCCESS;
1346}
1347
1348
1349
1350/**
1351 * Disables the Hyper-V TSC page.
1352 *
1353 * @returns VBox status code.
1354 * @param pVM The cross context VM structure.
1355 */
1356VMMR3_INT_DECL(int) gimR3HvDisableTscPage(PVM pVM)
1357{
1358 PGIMHV pHv = &pVM->gim.s.u.Hv;
1359 PGIMMMIO2REGION pRegion = &pHv->aMmio2Regions[GIM_HV_REF_TSC_PAGE_REGION_IDX];
1360 if (pRegion->fMapped)
1361 {
1362#if 0
1363 gimR3Mmio2Unmap(pVM, pRegion);
1364 Assert(!pRegion->fMapped);
1365#else
1366 pRegion->fMapped = false;
1367#endif
1368 LogRel(("GIM: HyperV: Disabled TSC page\n"));
1369
1370 TMR3CpuTickParavirtDisable(pVM);
1371 return VINF_SUCCESS;
1372 }
1373 return VERR_GIM_PVTSC_NOT_ENABLED;
1374}
1375
1376
1377/**
1378 * Disables the Hyper-V Hypercall page.
1379 *
1380 * @returns VBox status code.
1381 */
1382VMMR3_INT_DECL(int) gimR3HvDisableHypercallPage(PVM pVM)
1383{
1384 PGIMHV pHv = &pVM->gim.s.u.Hv;
1385 PGIMMMIO2REGION pRegion = &pHv->aMmio2Regions[GIM_HV_HYPERCALL_PAGE_REGION_IDX];
1386 if (pRegion->fMapped)
1387 {
1388#if 0
1389 gimR3Mmio2Unmap(pVM, pRegion);
1390 Assert(!pRegion->fMapped);
1391#else
1392 pRegion->fMapped = false;
1393#endif
1394 LogRel(("GIM: HyperV: Disabled Hypercall-page\n"));
1395 return VINF_SUCCESS;
1396 }
1397 return VERR_GIM_HYPERCALLS_NOT_ENABLED;
1398}
1399
1400
1401/**
1402 * Enables the Hyper-V Hypercall page.
1403 *
1404 * @returns VBox status code.
1405 * @param pVM The cross context VM structure.
1406 * @param GCPhysHypercallPage Where to map the hypercall page.
1407 */
1408VMMR3_INT_DECL(int) gimR3HvEnableHypercallPage(PVM pVM, RTGCPHYS GCPhysHypercallPage)
1409{
1410 PPDMDEVINSR3 pDevIns = pVM->gim.s.pDevInsR3;
1411 PGIMMMIO2REGION pRegion = &pVM->gim.s.u.Hv.aMmio2Regions[GIM_HV_HYPERCALL_PAGE_REGION_IDX];
1412 AssertPtrReturn(pDevIns, VERR_GIM_DEVICE_NOT_REGISTERED);
1413
1414 if (pRegion->fMapped)
1415 {
1416 /*
1417 * Is it already enabled at the given guest-address?
1418 */
1419 if (pRegion->GCPhysPage == GCPhysHypercallPage)
1420 return VINF_SUCCESS;
1421
1422 /*
1423 * If it's mapped at a different address, unmap the previous address.
1424 */
1425 int rc2 = gimR3HvDisableHypercallPage(pVM);
1426 AssertRC(rc2);
1427 }
1428
1429 /*
1430 * Map the hypercall-page at the specified address.
1431 */
1432 Assert(!pRegion->fMapped);
1433
1434 /** @todo this is buggy when large pages are used due to a PGM limitation, see
1435 * @bugref{7532}. Instead of the overlay style mapping, we just
1436 * rewrite guest memory directly. */
1437#if 0
1438 int rc = gimR3Mmio2Map(pVM, pRegion, GCPhysHypercallPage);
1439 if (RT_SUCCESS(rc))
1440 {
1441 Assert(pRegion->GCPhysPage == GCPhysHypercallPage);
1442
1443 /*
1444 * Patch the hypercall-page.
1445 */
1446 size_t cbWritten = 0;
1447 rc = VMMPatchHypercall(pVM, pRegion->pvPageR3, PAGE_SIZE, &cbWritten);
1448 if ( RT_SUCCESS(rc)
1449 && cbWritten < PAGE_SIZE)
1450 {
1451 uint8_t *pbLast = (uint8_t *)pRegion->pvPageR3 + cbWritten;
1452 *pbLast = 0xc3; /* RET */
1453
1454 /*
1455 * Notify VMM that hypercalls are now enabled for all VCPUs.
1456 */
1457 for (VMCPUID i = 0; i < pVM->cCpus; i++)
1458 VMMHypercallsEnable(&pVM->aCpus[i]);
1459
1460 LogRel(("GIM: HyperV: Enabled hypercall page at %#RGp\n", GCPhysHypercallPage));
1461 return VINF_SUCCESS;
1462 }
1463 else
1464 {
1465 if (rc == VINF_SUCCESS)
1466 rc = VERR_GIM_OPERATION_FAILED;
1467 LogRel(("GIM: HyperV: VMMPatchHypercall failed. rc=%Rrc cbWritten=%u\n", rc, cbWritten));
1468 }
1469
1470 gimR3Mmio2Unmap(pVM, pRegion);
1471 }
1472
1473 LogRel(("GIM: HyperV: gimR3Mmio2Map failed. rc=%Rrc\n", rc));
1474 return rc;
1475#else
1476 AssertReturn(pRegion->cbRegion == PAGE_SIZE, VERR_GIM_IPE_3);
1477 void *pvHypercallPage = RTMemAllocZ(PAGE_SIZE);
1478 if (RT_UNLIKELY(!pvHypercallPage))
1479 {
1480 LogRelFunc(("Failed to alloc %u bytes\n", PAGE_SIZE));
1481 return VERR_NO_MEMORY;
1482 }
1483
1484 /*
1485 * Patch the hypercall-page.
1486 */
1487 size_t cbWritten = 0;
1488 int rc = VMMPatchHypercall(pVM, pvHypercallPage, PAGE_SIZE, &cbWritten);
1489 if ( RT_SUCCESS(rc)
1490 && cbWritten < PAGE_SIZE)
1491 {
1492 uint8_t *pbLast = (uint8_t *)pvHypercallPage + cbWritten;
1493 *pbLast = 0xc3; /* RET */
1494
1495 rc = PGMPhysSimpleWriteGCPhys(pVM, GCPhysHypercallPage, pvHypercallPage, PAGE_SIZE);
1496 if (RT_SUCCESS(rc))
1497 {
1498 pRegion->GCPhysPage = GCPhysHypercallPage;
1499 pRegion->fMapped = true;
1500 LogRel(("GIM: HyperV: Enabled hypercall page at %#RGp\n", GCPhysHypercallPage));
1501 }
1502 else
1503 LogRel(("GIM: HyperV: PGMPhysSimpleWriteGCPhys failed during hypercall page setup. rc=%Rrc\n", rc));
1504 }
1505 else
1506 {
1507 if (rc == VINF_SUCCESS)
1508 rc = VERR_GIM_OPERATION_FAILED;
1509 LogRel(("GIM: HyperV: VMMPatchHypercall failed. rc=%Rrc cbWritten=%u\n", rc, cbWritten));
1510 }
1511
1512 RTMemFree(pvHypercallPage);
1513 return rc;
1514#endif
1515}
1516
1517
1518/**
1519 * Initializes Hyper-V guest hypercall support.
1520 *
1521 * @returns VBox status code.
1522 * @param pVM The cross context VM structure.
1523 */
1524static int gimR3HvInitHypercallSupport(PVM pVM)
1525{
1526 PGIMHV pHv = &pVM->gim.s.u.Hv;
1527 pHv->pbHypercallIn = (uint8_t *)RTMemAllocZ(GIM_HV_PAGE_SIZE);
1528 if (RT_LIKELY(pHv->pbHypercallIn))
1529 {
1530 pHv->pbHypercallOut = (uint8_t *)RTMemAllocZ(GIM_HV_PAGE_SIZE);
1531 if (RT_LIKELY(pHv->pbHypercallOut))
1532 return VINF_SUCCESS;
1533 RTMemFree(pHv->pbHypercallIn);
1534 }
1535 return VERR_NO_MEMORY;
1536}
1537
1538
1539/**
1540 * Terminates Hyper-V guest hypercall support.
1541 *
1542 * @param pVM The cross context VM structure.
1543 */
1544static void gimR3HvTermHypercallSupport(PVM pVM)
1545{
1546 PGIMHV pHv = &pVM->gim.s.u.Hv;
1547 RTMemFree(pHv->pbHypercallIn);
1548 pHv->pbHypercallIn = NULL;
1549
1550 RTMemFree(pHv->pbHypercallOut);
1551 pHv->pbHypercallOut = NULL;
1552}
1553
1554
1555/**
1556 * Initializes Hyper-V guest debug support.
1557 *
1558 * @returns VBox status code.
1559 * @param pVM The cross context VM structure.
1560 */
1561static int gimR3HvInitDebugSupport(PVM pVM)
1562{
1563 PGIMHV pHv = &pVM->gim.s.u.Hv;
1564 if ( (pHv->uPartFlags & GIM_HV_PART_FLAGS_DEBUGGING)
1565 || pHv->fIsInterfaceVs)
1566 {
1567 pHv->fDbgEnabled = true;
1568 pHv->pvDbgBuffer = RTMemAllocZ(PAGE_SIZE);
1569 if (!pHv->pvDbgBuffer)
1570 return VERR_NO_MEMORY;
1571 }
1572 return VINF_SUCCESS;
1573}
1574
1575
1576/**
1577 * Terminates Hyper-V guest debug support.
1578 *
1579 * @param pVM The cross context VM structure.
1580 */
1581static void gimR3HvTermDebugSupport(PVM pVM)
1582{
1583 PGIMHV pHv = &pVM->gim.s.u.Hv;
1584 if (pHv->pvDbgBuffer)
1585 {
1586 RTMemFree(pHv->pvDbgBuffer);
1587 pHv->pvDbgBuffer = NULL;
1588 }
1589}
1590
1591
1592/**
1593 * Reads data from a debugger connection, asynchronous.
1594 *
1595 * @returns VBox status code.
1596 * @param pVM The cross context VM structure.
1597 * @param pvBuf Where to read the data.
1598 * @param cbBuf Size of the read buffer @a pvBuf, must be >= @a cbRead.
1599 * @param cbRead Number of bytes to read.
1600 * @param pcbRead Where to store how many bytes were really read.
1601 * @param cMsTimeout Timeout of the read operation in milliseconds.
1602 * @param fUdpPkt Whether the debug data returned in @a pvBuf needs to be
1603 * encapsulated in a UDP frame.
1604 *
1605 * @thread EMT.
1606 */
1607VMMR3_INT_DECL(int) gimR3HvDebugRead(PVM pVM, void *pvBuf, uint32_t cbBuf, uint32_t cbRead, uint32_t *pcbRead,
1608 uint32_t cMsTimeout, bool fUdpPkt)
1609{
1610 NOREF(cMsTimeout); /** @todo implement timeout. */
1611 AssertCompile(sizeof(size_t) >= sizeof(uint32_t));
1612 AssertReturn(cbBuf >= cbRead, VERR_INVALID_PARAMETER);
1613
1614 int rc;
1615 if (!fUdpPkt)
1616 {
1617 /*
1618 * Read the raw debug data.
1619 */
1620 size_t cbReallyRead = cbRead;
1621 rc = gimR3DebugRead(pVM, pvBuf, &cbReallyRead, gimR3HvDebugBufReadCompleted);
1622 *pcbRead = (uint32_t)cbReallyRead;
1623 }
1624 else
1625 {
1626 /*
1627 * Guest requires UDP encapsulated frames.
1628 */
1629 PGIMHV pHv = &pVM->gim.s.u.Hv;
1630 rc = VERR_GIM_IPE_1;
1631 switch (pHv->enmDbgReply)
1632 {
1633 case GIMHVDEBUGREPLY_UDP:
1634 {
1635 size_t cbReallyRead = cbRead;
1636 rc = gimR3DebugRead(pVM, pvBuf, &cbReallyRead, gimR3HvDebugBufReadCompleted);
1637 if ( RT_SUCCESS(rc)
1638 && cbReallyRead > 0)
1639 {
1640 uint8_t abFrame[sizeof(RTNETETHERHDR) + RTNETIPV4_MIN_LEN + sizeof(RTNETUDP)];
1641 if (cbReallyRead + sizeof(abFrame) <= cbBuf)
1642 {
1643 /*
1644 * Windows guests pumps ethernet frames over the Hyper-V debug connection as
1645 * explained in gimR3HvHypercallPostDebugData(). Here, we reconstruct the packet
1646 * with the guest's self-chosen IP ARP address we saved in pHv->DbgGuestAddr.
1647 *
1648 * Note! We really need to pass the minimum IPv4 header length. The Windows 10 guest
1649 * is -not- happy if we include the IPv4 options field, i.e. using sizeof(RTNETIPV4)
1650 * instead of RTNETIPV4_MIN_LEN.
1651 */
1652 RT_ZERO(abFrame);
1653 PRTNETETHERHDR pEthHdr = (PRTNETETHERHDR)&abFrame[0];
1654 PRTNETIPV4 pIpHdr = (PRTNETIPV4) (pEthHdr + 1);
1655 PRTNETUDP pUdpHdr = (PRTNETUDP) ((uint8_t *)pIpHdr + RTNETIPV4_MIN_LEN);
1656
1657 /* Ethernet */
1658 pEthHdr->EtherType = RT_H2N_U16_C(RTNET_ETHERTYPE_IPV4);
1659 /* IPv4 */
1660 pIpHdr->ip_v = 4;
1661 pIpHdr->ip_hl = RTNETIPV4_MIN_LEN / sizeof(uint32_t);
1662 pIpHdr->ip_tos = 0;
1663 pIpHdr->ip_len = RT_H2N_U16((uint16_t)cbReallyRead + sizeof(RTNETUDP) + RTNETIPV4_MIN_LEN);
1664 pIpHdr->ip_id = 0;
1665 pIpHdr->ip_off = 0;
1666 pIpHdr->ip_ttl = 255;
1667 pIpHdr->ip_p = RTNETIPV4_PROT_UDP;
1668 pIpHdr->ip_sum = 0;
1669 pIpHdr->ip_src.u = 0;
1670 pIpHdr->ip_dst.u = pHv->DbgGuestIp4Addr.u;
1671 pIpHdr->ip_sum = RTNetIPv4HdrChecksum(pIpHdr);
1672 /* UDP */
1673 pUdpHdr->uh_dport = pHv->uUdpGuestSrcPort;
1674 pUdpHdr->uh_sport = pHv->uUdpGuestDstPort;
1675 pUdpHdr->uh_ulen = RT_H2N_U16_C((uint16_t)cbReallyRead + sizeof(*pUdpHdr));
1676
1677 /* Make room by moving the payload and prepending the headers. */
1678 uint8_t *pbData = (uint8_t *)pvBuf;
1679 memmove(pbData + sizeof(abFrame), pbData, cbReallyRead);
1680 memcpy(pbData, &abFrame[0], sizeof(abFrame));
1681
1682 /* Update the adjusted sizes. */
1683 cbReallyRead += sizeof(abFrame);
1684 }
1685 else
1686 rc = VERR_BUFFER_UNDERFLOW;
1687 }
1688 *pcbRead = (uint32_t)cbReallyRead;
1689 break;
1690 }
1691
1692 case GIMHVDEBUGREPLY_ARP_REPLY:
1693 {
1694 uint32_t const cbArpReplyPkt = sizeof(g_abArpReply);
1695 if (cbBuf >= cbArpReplyPkt)
1696 {
1697 memcpy(pvBuf, g_abArpReply, cbArpReplyPkt);
1698 rc = VINF_SUCCESS;
1699 *pcbRead = cbArpReplyPkt;
1700 pHv->enmDbgReply = GIMHVDEBUGREPLY_ARP_REPLY_SENT;
1701 }
1702 else
1703 {
1704 rc = VERR_BUFFER_UNDERFLOW;
1705 *pcbRead = 0;
1706 }
1707 break;
1708 }
1709
1710 case GIMHVDEBUGREPLY_DHCP_OFFER:
1711 {
1712 uint32_t const cbDhcpOfferPkt = sizeof(g_abDhcpOffer);
1713 if (cbBuf >= cbDhcpOfferPkt)
1714 {
1715 memcpy(pvBuf, g_abDhcpOffer, cbDhcpOfferPkt);
1716 PRTNETETHERHDR pEthHdr = (PRTNETETHERHDR)pvBuf;
1717 PRTNETIPV4 pIpHdr = (PRTNETIPV4) (pEthHdr + 1);
1718 PRTNETUDP pUdpHdr = (PRTNETUDP) ((uint8_t *)pIpHdr + RTNETIPV4_MIN_LEN);
1719 PRTNETBOOTP pBootpHdr = (PRTNETBOOTP) (pUdpHdr + 1);
1720 pBootpHdr->bp_xid = pHv->uDbgBootpXId;
1721
1722 rc = VINF_SUCCESS;
1723 *pcbRead = cbDhcpOfferPkt;
1724 pHv->enmDbgReply = GIMHVDEBUGREPLY_DHCP_OFFER_SENT;
1725 LogRel(("GIM: HyperV: Debug DHCP offered IP address %RTnaipv4, transaction Id %#x\n", pBootpHdr->bp_yiaddr,
1726 RT_N2H_U32(pHv->uDbgBootpXId)));
1727 }
1728 else
1729 {
1730 rc = VERR_BUFFER_UNDERFLOW;
1731 *pcbRead = 0;
1732 }
1733 break;
1734 }
1735
1736 case GIMHVDEBUGREPLY_DHCP_ACK:
1737 {
1738 uint32_t const cbDhcpAckPkt = sizeof(g_abDhcpAck);
1739 if (cbBuf >= cbDhcpAckPkt)
1740 {
1741 memcpy(pvBuf, g_abDhcpAck, cbDhcpAckPkt);
1742 PRTNETETHERHDR pEthHdr = (PRTNETETHERHDR)pvBuf;
1743 PRTNETIPV4 pIpHdr = (PRTNETIPV4) (pEthHdr + 1);
1744 PRTNETUDP pUdpHdr = (PRTNETUDP) ((uint8_t *)pIpHdr + RTNETIPV4_MIN_LEN);
1745 PRTNETBOOTP pBootpHdr = (PRTNETBOOTP) (pUdpHdr + 1);
1746 pBootpHdr->bp_xid = pHv->uDbgBootpXId;
1747
1748 rc = VINF_SUCCESS;
1749 *pcbRead = cbDhcpAckPkt;
1750 pHv->enmDbgReply = GIMHVDEBUGREPLY_DHCP_ACK_SENT;
1751 LogRel(("GIM: HyperV: Debug DHCP acknowledged IP address %RTnaipv4, transaction Id %#x\n",
1752 pBootpHdr->bp_yiaddr, RT_N2H_U32(pHv->uDbgBootpXId)));
1753 }
1754 else
1755 {
1756 rc = VERR_BUFFER_UNDERFLOW;
1757 *pcbRead = 0;
1758 }
1759 break;
1760 }
1761
1762 case GIMHVDEBUGREPLY_ARP_REPLY_SENT:
1763 case GIMHVDEBUGREPLY_DHCP_OFFER_SENT:
1764 case GIMHVDEBUGREPLY_DHCP_ACK_SENT:
1765 {
1766 rc = VINF_SUCCESS;
1767 *pcbRead = 0;
1768 break;
1769 }
1770
1771 default:
1772 {
1773 AssertMsgFailed(("GIM: HyperV: Invalid/unimplemented debug reply type %u\n", pHv->enmDbgReply));
1774 rc = VERR_INTERNAL_ERROR_2;
1775 }
1776 }
1777 Assert(rc != VERR_GIM_IPE_1);
1778
1779#ifdef DEBUG_ramshankar
1780 if ( rc == VINF_SUCCESS
1781 && *pcbRead > 0)
1782 {
1783 RTSOCKET hSocket;
1784 int rc2 = RTUdpCreateClientSocket("localhost", 52000, NULL, &hSocket);
1785 if (RT_SUCCESS(rc2))
1786 {
1787 size_t cbTmpWrite = *pcbRead;
1788 RTSocketWriteNB(hSocket, pvBuf, *pcbRead, &cbTmpWrite); NOREF(cbTmpWrite);
1789 RTSocketClose(hSocket);
1790 }
1791 }
1792#endif
1793 }
1794
1795 return rc;
1796}
1797
1798
1799/**
1800 * Writes data to the debugger connection, asynchronous.
1801 *
1802 * @returns VBox status code.
1803 * @param pVM The cross context VM structure.
1804 * @param pvData Pointer to the data to be written.
1805 * @param cbWrite Size of the write buffer @a pvData.
1806 * @param pcbWritten Where to store the number of bytes written.
1807 * @param fUdpPkt Whether the debug data in @a pvData is encapsulated in a
1808 * UDP frame.
1809 *
1810 * @thread EMT.
1811 */
1812VMMR3_INT_DECL(int) gimR3HvDebugWrite(PVM pVM, void *pvData, uint32_t cbWrite, uint32_t *pcbWritten, bool fUdpPkt)
1813{
1814 Assert(cbWrite > 0);
1815
1816 PGIMHV pHv = &pVM->gim.s.u.Hv;
1817 bool fIgnorePkt = false;
1818 uint8_t *pbData = (uint8_t *)pvData;
1819 if (fUdpPkt)
1820 {
1821#ifdef DEBUG_ramshankar
1822 RTSOCKET hSocket;
1823 int rc2 = RTUdpCreateClientSocket("localhost", 52000, NULL, &hSocket);
1824 if (RT_SUCCESS(rc2))
1825 {
1826 size_t cbTmpWrite = cbWrite;
1827 RTSocketWriteNB(hSocket, pbData, cbWrite, &cbTmpWrite); NOREF(cbTmpWrite);
1828 RTSocketClose(hSocket);
1829 }
1830#endif
1831 /*
1832 * Windows guests sends us ethernet frames over the Hyper-V debug connection.
1833 * It sends DHCP/ARP queries with zero'd out MAC addresses and requires fudging up the
1834 * packets somewhere.
1835 *
1836 * The Microsoft WinDbg debugger talks UDP and thus only expects the actual debug
1837 * protocol payload.
1838 *
1839 * If the guest is configured with the "nodhcp" option it sends ARP queries with
1840 * a self-chosen IP and after a couple of attempts of receiving no replies, the guest
1841 * picks its own IP address. After this, the guest starts sending the UDP packets
1842 * we require. We thus ignore the initial ARP packets until the guest eventually
1843 * starts talking UDP. Then we can finally feed the UDP payload over the debug
1844 * connection.
1845 *
1846 * When 'kdvm.dll' is the debug transport in the guest (Windows 7), it doesn't bother
1847 * with this DHCP/ARP phase. It starts sending debug data in a UDP frame right away.
1848 */
1849 if (cbWrite > sizeof(RTNETETHERHDR))
1850 {
1851 PCRTNETETHERHDR pEtherHdr = (PCRTNETETHERHDR)pbData;
1852 if (pEtherHdr->EtherType == RT_H2N_U16_C(RTNET_ETHERTYPE_IPV4))
1853 {
1854 if (cbWrite > sizeof(RTNETETHERHDR) + RTNETIPV4_MIN_LEN + RTNETUDP_MIN_LEN)
1855 {
1856 size_t const cbMaxIpHdr = cbWrite - sizeof(RTNETETHERHDR) - sizeof(RTNETUDP) - 1;
1857 size_t const cbMaxIpPkt = cbWrite - sizeof(RTNETETHERHDR);
1858 PCRTNETIPV4 pIp4Hdr = (PCRTNETIPV4)(pbData + sizeof(RTNETETHERHDR));
1859 bool const fValidIp4 = RTNetIPv4IsHdrValid(pIp4Hdr, cbMaxIpHdr, cbMaxIpPkt, false /*fChecksum*/);
1860 if ( fValidIp4
1861 && pIp4Hdr->ip_p == RTNETIPV4_PROT_UDP)
1862 {
1863 uint32_t const cbIpHdr = pIp4Hdr->ip_hl * 4;
1864 uint32_t const cbMaxUdpPkt = cbWrite - sizeof(RTNETETHERHDR) - cbIpHdr;
1865 PCRTNETUDP pUdpHdr = (PCRTNETUDP)((uint8_t *)pIp4Hdr + cbIpHdr);
1866 if ( pUdpHdr->uh_ulen > RT_H2N_U16(sizeof(RTNETUDP))
1867 && pUdpHdr->uh_ulen <= RT_H2N_U16((uint16_t)cbMaxUdpPkt))
1868 {
1869 /*
1870 * Check for DHCP.
1871 */
1872 bool fBuggyPkt = false;
1873 size_t const cbUdpPkt = cbMaxIpPkt - cbIpHdr;
1874 if ( pUdpHdr->uh_dport == RT_N2H_U16_C(RTNETIPV4_PORT_BOOTPS)
1875 && pUdpHdr->uh_sport == RT_N2H_U16_C(RTNETIPV4_PORT_BOOTPC))
1876 {
1877 PCRTNETBOOTP pDhcpPkt = (PCRTNETBOOTP)(pUdpHdr + 1);
1878 uint8_t bMsgType;
1879 if ( cbMaxIpPkt >= cbIpHdr + RTNETUDP_MIN_LEN + RTNETBOOTP_DHCP_MIN_LEN
1880 && RTNetIPv4IsDHCPValid(pUdpHdr, pDhcpPkt, cbUdpPkt - sizeof(*pUdpHdr), &bMsgType))
1881 {
1882 switch (bMsgType)
1883 {
1884 case RTNET_DHCP_MT_DISCOVER:
1885 pHv->enmDbgReply = GIMHVDEBUGREPLY_DHCP_OFFER;
1886 pHv->uDbgBootpXId = pDhcpPkt->bp_xid;
1887 break;
1888 case RTNET_DHCP_MT_REQUEST:
1889 pHv->enmDbgReply = GIMHVDEBUGREPLY_DHCP_ACK;
1890 pHv->uDbgBootpXId = pDhcpPkt->bp_xid;
1891 break;
1892 default:
1893 LogRelMax(5, ("GIM: HyperV: Debug DHCP MsgType %#x not implemented! Packet dropped\n",
1894 bMsgType));
1895 break;
1896 }
1897 fIgnorePkt = true;
1898 }
1899 else if ( pIp4Hdr->ip_src.u == GIMHV_DEBUGCLIENT_IPV4
1900 && pIp4Hdr->ip_dst.u == 0)
1901 {
1902 /*
1903 * Windows 8.1 seems to be sending malformed BOOTP packets at the final stage of the
1904 * debugger sequence. It appears that a previously sent DHCP request buffer wasn't cleared
1905 * in the guest and they re-use it instead of sending a zero destination+source port packet
1906 * as expected below.
1907 *
1908 * We workaround Microsoft's bug here, or at least, I'm classifying it as a bug to
1909 * preserve my own sanity, see @bugref{8006#c54}.
1910 */
1911 fBuggyPkt = true;
1912 }
1913 }
1914
1915 if ( ( !pUdpHdr->uh_dport
1916 && !pUdpHdr->uh_sport)
1917 || fBuggyPkt)
1918 {
1919 /*
1920 * Extract the UDP payload and pass it to the debugger and record the guest IP address.
1921 *
1922 * Hyper-V sends UDP debugger packets with source and destination port as 0 except in the
1923 * aforementioned buggy case. The buggy packet case requires us to remember the ports and
1924 * reply to them, otherwise the guest won't receive the replies we sent with port 0.
1925 */
1926 uint32_t const cbFrameHdr = sizeof(RTNETETHERHDR) + cbIpHdr + sizeof(RTNETUDP);
1927 pbData += cbFrameHdr;
1928 cbWrite -= cbFrameHdr;
1929 pHv->DbgGuestIp4Addr.u = pIp4Hdr->ip_src.u;
1930 pHv->uUdpGuestDstPort = pUdpHdr->uh_dport;
1931 pHv->uUdpGuestSrcPort = pUdpHdr->uh_sport;
1932 pHv->enmDbgReply = GIMHVDEBUGREPLY_UDP;
1933 }
1934 else
1935 {
1936 LogFlow(("GIM: HyperV: Ignoring UDP packet SourcePort=%u DstPort=%u\n", pUdpHdr->uh_sport,
1937 pUdpHdr->uh_dport));
1938 fIgnorePkt = true;
1939 }
1940 }
1941 else
1942 {
1943 LogFlow(("GIM: HyperV: Ignoring malformed UDP packet. cbMaxUdpPkt=%u UdpPkt.len=%u\n", cbMaxUdpPkt,
1944 RT_N2H_U16(pUdpHdr->uh_ulen)));
1945 fIgnorePkt = true;
1946 }
1947 }
1948 else
1949 {
1950 LogFlow(("GIM: HyperV: Ignoring non-IP / non-UDP packet. fValidIp4=%RTbool Proto=%u\n", fValidIp4,
1951 pIp4Hdr->ip_p));
1952 fIgnorePkt = true;
1953 }
1954 }
1955 else
1956 {
1957 LogFlow(("GIM: HyperV: Ignoring IPv4 packet; too short to be valid UDP. cbWrite=%u\n", cbWrite));
1958 fIgnorePkt = true;
1959 }
1960 }
1961 else if (pEtherHdr->EtherType == RT_H2N_U16_C(RTNET_ETHERTYPE_ARP))
1962 {
1963 /*
1964 * Check for targetted ARP query.
1965 */
1966 PCRTNETARPHDR pArpHdr = (PCRTNETARPHDR)(pbData + sizeof(RTNETETHERHDR));
1967 if ( pArpHdr->ar_hlen == sizeof(RTMAC)
1968 && pArpHdr->ar_plen == sizeof(RTNETADDRIPV4)
1969 && pArpHdr->ar_htype == RT_H2N_U16(RTNET_ARP_ETHER)
1970 && pArpHdr->ar_ptype == RT_H2N_U16(RTNET_ETHERTYPE_IPV4))
1971 {
1972 uint16_t uArpOp = pArpHdr->ar_oper;
1973 if (uArpOp == RT_H2N_U16_C(RTNET_ARPOP_REQUEST))
1974 {
1975 PCRTNETARPIPV4 pArpPkt = (PCRTNETARPIPV4)pArpHdr;
1976 bool fGratuitous = pArpPkt->ar_spa.u == pArpPkt->ar_tpa.u;
1977 if ( !fGratuitous
1978 && pArpPkt->ar_spa.u == GIMHV_DEBUGCLIENT_IPV4
1979 && pArpPkt->ar_tpa.u == GIMHV_DEBUGSERVER_IPV4)
1980 {
1981 pHv->enmDbgReply = GIMHVDEBUGREPLY_ARP_REPLY;
1982 }
1983 }
1984 }
1985 fIgnorePkt = true;
1986 }
1987 else
1988 {
1989 LogFlow(("GIM: HyperV: Ignoring non-IP packet. Ethertype=%#x\n", RT_N2H_U16(pEtherHdr->EtherType)));
1990 fIgnorePkt = true;
1991 }
1992 }
1993 }
1994
1995 if (!fIgnorePkt)
1996 {
1997 AssertCompile(sizeof(size_t) >= sizeof(uint32_t));
1998 size_t cbWriteBuf = cbWrite;
1999 int rc = gimR3DebugWrite(pVM, pbData, &cbWriteBuf);
2000 if ( RT_SUCCESS(rc)
2001 && cbWriteBuf == cbWrite)
2002 *pcbWritten = (uint32_t)cbWriteBuf;
2003 else
2004 *pcbWritten = 0;
2005 }
2006 else
2007 *pcbWritten = cbWrite;
2008
2009 return VINF_SUCCESS;
2010}
2011
2012
2013/**
2014 * Performs the HvPostDebugData hypercall.
2015 *
2016 * @returns VBox status code.
2017 * @param pVM The cross context VM structure.
2018 * @param prcHv Where to store the result of the hypercall operation.
2019 *
2020 * @thread EMT.
2021 */
2022VMMR3_INT_DECL(int) gimR3HvHypercallPostDebugData(PVM pVM, int *prcHv)
2023{
2024 AssertPtr(pVM);
2025 AssertPtr(prcHv);
2026 PGIMHV pHv = &pVM->gim.s.u.Hv;
2027 int rcHv = GIM_HV_STATUS_OPERATION_DENIED;
2028
2029 /*
2030 * Grab the parameters.
2031 */
2032 PGIMHVDEBUGPOSTIN pIn = (PGIMHVDEBUGPOSTIN)pHv->pbHypercallIn;
2033 AssertPtrReturn(pIn, VERR_GIM_IPE_1);
2034 uint32_t cbWrite = pIn->cbWrite;
2035 uint32_t fFlags = pIn->fFlags;
2036 uint8_t *pbData = ((uint8_t *)pIn) + sizeof(PGIMHVDEBUGPOSTIN);
2037
2038 PGIMHVDEBUGPOSTOUT pOut = (PGIMHVDEBUGPOSTOUT)pHv->pbHypercallOut;
2039
2040 /*
2041 * Perform the hypercall.
2042 */
2043#if 0
2044 /* Currently disabled as Windows 10 guest passes us undocumented flags. */
2045 if (fFlags & ~GIM_HV_DEBUG_POST_OPTIONS_MASK))
2046 rcHv = GIM_HV_STATUS_INVALID_PARAMETER;
2047#else
2048 RT_NOREF1(fFlags);
2049#endif
2050 if (cbWrite > GIM_HV_DEBUG_MAX_DATA_SIZE)
2051 rcHv = GIM_HV_STATUS_INVALID_PARAMETER;
2052 else if (!cbWrite)
2053 {
2054 rcHv = GIM_HV_STATUS_SUCCESS;
2055 pOut->cbPending = 0;
2056 }
2057 else if (cbWrite > 0)
2058 {
2059 uint32_t cbWritten = 0;
2060 int rc2 = gimR3HvDebugWrite(pVM, pbData, cbWrite, &cbWritten, pHv->fIsVendorMsHv /*fUdpPkt*/);
2061 if ( RT_SUCCESS(rc2)
2062 && cbWritten == cbWrite)
2063 {
2064 pOut->cbPending = 0;
2065 rcHv = GIM_HV_STATUS_SUCCESS;
2066 }
2067 else
2068 rcHv = GIM_HV_STATUS_INSUFFICIENT_BUFFER;
2069 }
2070
2071 /*
2072 * Update the guest memory with result.
2073 */
2074 int rc = PGMPhysSimpleWriteGCPhys(pVM, pHv->GCPhysHypercallOut, pHv->pbHypercallOut, sizeof(GIMHVDEBUGPOSTOUT));
2075 if (RT_FAILURE(rc))
2076 {
2077 LogRelMax(10, ("GIM: HyperV: HvPostDebugData failed to update guest memory. rc=%Rrc\n", rc));
2078 rc = VERR_GIM_HYPERCALL_MEMORY_WRITE_FAILED;
2079 }
2080 else
2081 Assert(rc == VINF_SUCCESS);
2082
2083 *prcHv = rcHv;
2084 return rc;
2085}
2086
2087
2088/**
2089 * Performs the HvRetrieveDebugData hypercall.
2090 *
2091 * @returns VBox status code.
2092 * @param pVM The cross context VM structure.
2093 * @param prcHv Where to store the result of the hypercall operation.
2094 *
2095 * @thread EMT.
2096 */
2097VMMR3_INT_DECL(int) gimR3HvHypercallRetrieveDebugData(PVM pVM, int *prcHv)
2098{
2099 AssertPtr(pVM);
2100 AssertPtr(prcHv);
2101 PGIMHV pHv = &pVM->gim.s.u.Hv;
2102 int rcHv = GIM_HV_STATUS_OPERATION_DENIED;
2103
2104 /*
2105 * Grab the parameters.
2106 */
2107 PGIMHVDEBUGRETRIEVEIN pIn = (PGIMHVDEBUGRETRIEVEIN)pHv->pbHypercallIn;
2108 AssertPtrReturn(pIn, VERR_GIM_IPE_1);
2109 uint32_t cbRead = pIn->cbRead;
2110 uint32_t fFlags = pIn->fFlags;
2111 uint64_t uTimeout = pIn->u64Timeout;
2112 uint32_t cMsTimeout = (fFlags & GIM_HV_DEBUG_RETREIVE_LOOP) ? (uTimeout * 100) / RT_NS_1MS_64 : 0;
2113
2114 PGIMHVDEBUGRETRIEVEOUT pOut = (PGIMHVDEBUGRETRIEVEOUT)pHv->pbHypercallOut;
2115 AssertPtrReturn(pOut, VERR_GIM_IPE_2);
2116 uint32_t *pcbReallyRead = &pOut->cbRead;
2117 uint32_t *pcbRemainingRead = &pOut->cbRemaining;
2118 void *pvData = ((uint8_t *)pOut) + sizeof(GIMHVDEBUGRETRIEVEOUT);
2119
2120 /*
2121 * Perform the hypercall.
2122 */
2123 *pcbReallyRead = 0;
2124 *pcbRemainingRead = cbRead;
2125#if 0
2126 /* Currently disabled as Windows 10 guest passes us undocumented flags. */
2127 if (fFlags & ~GIM_HV_DEBUG_RETREIVE_OPTIONS_MASK)
2128 rcHv = GIM_HV_STATUS_INVALID_PARAMETER;
2129#endif
2130 if (cbRead > GIM_HV_DEBUG_MAX_DATA_SIZE)
2131 rcHv = GIM_HV_STATUS_INVALID_PARAMETER;
2132 else if (fFlags & GIM_HV_DEBUG_RETREIVE_TEST_ACTIVITY)
2133 rcHv = GIM_HV_STATUS_SUCCESS; /** @todo implement this. */
2134 else if (!cbRead)
2135 rcHv = GIM_HV_STATUS_SUCCESS;
2136 else if (cbRead > 0)
2137 {
2138 int rc2 = gimR3HvDebugRead(pVM, pvData, GIM_HV_PAGE_SIZE, cbRead, pcbReallyRead, cMsTimeout,
2139 pHv->fIsVendorMsHv /*fUdpPkt*/);
2140 Assert(*pcbReallyRead <= cbRead);
2141 if ( RT_SUCCESS(rc2)
2142 && *pcbReallyRead > 0)
2143 {
2144 *pcbRemainingRead = cbRead - *pcbReallyRead;
2145 rcHv = GIM_HV_STATUS_SUCCESS;
2146 }
2147 else
2148 rcHv = GIM_HV_STATUS_NO_DATA;
2149 }
2150
2151 /*
2152 * Update the guest memory with result.
2153 */
2154 int rc = PGMPhysSimpleWriteGCPhys(pVM, pHv->GCPhysHypercallOut, pHv->pbHypercallOut,
2155 sizeof(GIMHVDEBUGRETRIEVEOUT) + *pcbReallyRead);
2156 if (RT_FAILURE(rc))
2157 {
2158 LogRelMax(10, ("GIM: HyperV: HvRetrieveDebugData failed to update guest memory. rc=%Rrc\n", rc));
2159 rc = VERR_GIM_HYPERCALL_MEMORY_WRITE_FAILED;
2160 }
2161 else
2162 Assert(rc == VINF_SUCCESS);
2163
2164 *prcHv = rcHv;
2165 return rc;
2166}
2167
2168
2169/**
2170 * Performs the HvExtCallQueryCapabilities extended hypercall.
2171 *
2172 * @returns VBox status code.
2173 * @param pVM The cross context VM structure.
2174 * @param prcHv Where to store the result of the hypercall operation.
2175 *
2176 * @thread EMT.
2177 */
2178VMMR3_INT_DECL(int) gimR3HvHypercallExtQueryCap(PVM pVM, int *prcHv)
2179{
2180 AssertPtr(pVM);
2181 AssertPtr(prcHv);
2182 PGIMHV pHv = &pVM->gim.s.u.Hv;
2183
2184 /*
2185 * Grab the parameters.
2186 */
2187 PGIMHVEXTQUERYCAP pOut = (PGIMHVEXTQUERYCAP)pHv->pbHypercallOut;
2188
2189 /*
2190 * Perform the hypercall.
2191 */
2192 pOut->fCapabilities = GIM_HV_EXT_HYPERCALL_CAP_ZERO_MEM;
2193
2194 /*
2195 * Update the guest memory with result.
2196 */
2197 int rcHv;
2198 int rc = PGMPhysSimpleWriteGCPhys(pVM, pHv->GCPhysHypercallOut, pHv->pbHypercallOut, sizeof(GIMHVEXTQUERYCAP));
2199 if (RT_SUCCESS(rc))
2200 {
2201 rcHv = GIM_HV_STATUS_SUCCESS;
2202 LogRel(("GIM: HyperV: Queried extended hypercall capabilities %#RX64 at %#RGp\n", pOut->fCapabilities,
2203 pHv->GCPhysHypercallOut));
2204 }
2205 else
2206 {
2207 rcHv = GIM_HV_STATUS_OPERATION_DENIED;
2208 LogRelMax(10, ("GIM: HyperV: HvHypercallExtQueryCap failed to update guest memory. rc=%Rrc\n", rc));
2209 rc = VERR_GIM_HYPERCALL_MEMORY_WRITE_FAILED;
2210 }
2211
2212 *prcHv = rcHv;
2213 return rc;
2214}
2215
2216
2217/**
2218 * Performs the HvExtCallGetBootZeroedMemory extended hypercall.
2219 *
2220 * @returns VBox status code.
2221 * @param pVM The cross context VM structure.
2222 * @param prcHv Where to store the result of the hypercall operation.
2223 *
2224 * @thread EMT.
2225 */
2226VMMR3_INT_DECL(int) gimR3HvHypercallExtGetBootZeroedMem(PVM pVM, int *prcHv)
2227{
2228 AssertPtr(pVM);
2229 AssertPtr(prcHv);
2230 PGIMHV pHv = &pVM->gim.s.u.Hv;
2231
2232 /*
2233 * Grab the parameters.
2234 */
2235 PGIMHVEXTGETBOOTZEROMEM pOut = (PGIMHVEXTGETBOOTZEROMEM)pHv->pbHypercallOut;
2236
2237 /*
2238 * Perform the hypercall.
2239 */
2240 uint32_t const cRanges = PGMR3PhysGetRamRangeCount(pVM);
2241 pOut->cPages = 0;
2242 for (uint32_t iRange = 0; iRange < cRanges; iRange++)
2243 {
2244 RTGCPHYS GCPhysStart;
2245 RTGCPHYS GCPhysEnd;
2246 int rc = PGMR3PhysGetRange(pVM, iRange, &GCPhysStart, &GCPhysEnd, NULL /* pszDesc */, NULL /* fIsMmio */);
2247 if (RT_FAILURE(rc))
2248 {
2249 LogRelMax(10, ("GIM: HyperV: HvHypercallExtGetBootZeroedMem: PGMR3PhysGetRange failed for iRange(%u) rc=%Rrc\n",
2250 iRange, rc));
2251 *prcHv = GIM_HV_STATUS_OPERATION_DENIED;
2252 return rc;
2253 }
2254
2255 RTGCPHYS const cbRange = RT_ALIGN(GCPhysEnd - GCPhysStart + 1, PAGE_SIZE);
2256 pOut->cPages += cbRange >> GIM_HV_PAGE_SHIFT;
2257 if (iRange == 0)
2258 pOut->GCPhysStart = GCPhysStart;
2259 }
2260
2261 /*
2262 * Update the guest memory with result.
2263 */
2264 int rcHv;
2265 int rc = PGMPhysSimpleWriteGCPhys(pVM, pHv->GCPhysHypercallOut, pHv->pbHypercallOut, sizeof(GIMHVEXTGETBOOTZEROMEM));
2266 if (RT_SUCCESS(rc))
2267 {
2268 LogRel(("GIM: HyperV: Queried boot zeroed guest memory range (starting at %#RGp spanning %u pages) at %#RGp\n",
2269 pOut->GCPhysStart, pOut->cPages, pHv->GCPhysHypercallOut));
2270 rcHv = GIM_HV_STATUS_SUCCESS;
2271 }
2272 else
2273 {
2274 rcHv = GIM_HV_STATUS_OPERATION_DENIED;
2275 LogRelMax(10, ("GIM: HyperV: HvHypercallExtGetBootZeroedMem failed to update guest memory. rc=%Rrc\n", rc));
2276 rc = VERR_GIM_HYPERCALL_MEMORY_WRITE_FAILED;
2277 }
2278
2279 *prcHv = rcHv;
2280 return rc;
2281}
2282
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