VirtualBox

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

Last change on this file since 58436 was 58436, checked in by vboxsync, 9 years ago

VMM/GIM: Comments.

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