VirtualBox

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

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

GIM: Saved state compatibility.

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