VirtualBox

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

Last change on this file since 62359 was 62359, checked in by vboxsync, 8 years ago

VMM/GIM: Doxygen build fix.

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