VirtualBox

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

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

VMM/GIM: Removed some dead code.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 67.9 KB
Line 
1/* $Id: GIMHv.cpp 58564 2015-11-04 13:53:54Z 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
860 uint8_t bDelim;
861 return SSMR3GetU8(pSSM, &bDelim);
862}
863
864
865/**
866 * Enables the Hyper-V TSC page.
867 *
868 * @returns VBox status code.
869 * @param pVM The cross context VM structure.
870 * @param GCPhysTscPage Where to map the TSC page.
871 * @param fUseThisTscSeq Whether to set the TSC sequence number to the one
872 * specified in @a uTscSeq.
873 * @param uTscSeq The TSC sequence value to use. Ignored if
874 * @a fUseThisTscSeq is false.
875 */
876VMMR3_INT_DECL(int) gimR3HvEnableTscPage(PVM pVM, RTGCPHYS GCPhysTscPage, bool fUseThisTscSeq, uint32_t uTscSeq)
877{
878 PPDMDEVINSR3 pDevIns = pVM->gim.s.pDevInsR3;
879 PGIMMMIO2REGION pRegion = &pVM->gim.s.u.Hv.aMmio2Regions[GIM_HV_REF_TSC_PAGE_REGION_IDX];
880 AssertPtrReturn(pDevIns, VERR_GIM_DEVICE_NOT_REGISTERED);
881
882 int rc;
883 if (pRegion->fMapped)
884 {
885 /*
886 * Is it already enabled at the given guest-address?
887 */
888 if (pRegion->GCPhysPage == GCPhysTscPage)
889 return VINF_SUCCESS;
890
891 /*
892 * If it's mapped at a different address, unmap the previous address.
893 */
894 rc = gimR3HvDisableTscPage(pVM);
895 AssertRC(rc);
896 }
897
898 /*
899 * Map the TSC-page at the specified address.
900 */
901 Assert(!pRegion->fMapped);
902
903 /** @todo this is buggy when large pages are used due to a PGM limitation, see
904 * @bugref{7532}. Instead of the overlay style mapping, we just
905 * rewrite guest memory directly. */
906#if 0
907 rc = GIMR3Mmio2Map(pVM, pRegion, GCPhysTscPage);
908 if (RT_SUCCESS(rc))
909 {
910 Assert(pRegion->GCPhysPage == GCPhysTscPage);
911
912 /*
913 * Update the TSC scale. Windows guests expect a non-zero TSC sequence, otherwise
914 * they fallback to using the reference count MSR which is not ideal in terms of VM-exits.
915 *
916 * Also, Hyper-V normalizes the time in 10 MHz, see:
917 * http://technet.microsoft.com/it-it/sysinternals/dn553408%28v=vs.110%29
918 */
919 PGIMHVREFTSC pRefTsc = (PGIMHVREFTSC)pRegion->pvPageR3;
920 Assert(pRefTsc);
921
922 PGIMHV pHv = &pVM->gim.s.u.Hv;
923 uint64_t const u64TscKHz = pHv->cTscTicksPerSecond / UINT64_C(1000);
924 uint32_t u32TscSeq = 1;
925 if ( fUseThisTscSeq
926 && uTscSeq < UINT32_C(0xfffffffe))
927 u32TscSeq = uTscSeq + 1;
928 pRefTsc->u32TscSequence = u32TscSeq;
929 pRefTsc->u64TscScale = ((INT64_C(10000) << 32) / u64TscKHz) << 32;
930 pRefTsc->i64TscOffset = 0;
931
932 LogRel(("GIM: HyperV: Enabled TSC page at %#RGp - u64TscScale=%#RX64 u64TscKHz=%#RX64 (%'RU64) Seq=%#RU32\n",
933 GCPhysTscPage, pRefTsc->u64TscScale, u64TscKHz, u64TscKHz, pRefTsc->u32TscSequence));
934
935 TMR3CpuTickParavirtEnable(pVM);
936 return VINF_SUCCESS;
937 }
938 else
939 LogRelFunc(("GIMR3Mmio2Map failed. rc=%Rrc\n", rc));
940 return VERR_GIM_OPERATION_FAILED;
941#else
942 AssertReturn(pRegion->cbRegion == PAGE_SIZE, VERR_GIM_IPE_2);
943 PGIMHVREFTSC pRefTsc = (PGIMHVREFTSC)RTMemAllocZ(PAGE_SIZE);
944 if (RT_UNLIKELY(!pRefTsc))
945 {
946 LogRelFunc(("Failed to alloc %u bytes\n", PAGE_SIZE));
947 return VERR_NO_MEMORY;
948 }
949
950 PGIMHV pHv = &pVM->gim.s.u.Hv;
951 uint64_t const u64TscKHz = pHv->cTscTicksPerSecond / UINT64_C(1000);
952 uint32_t u32TscSeq = 1;
953 if ( fUseThisTscSeq
954 && uTscSeq < UINT32_C(0xfffffffe))
955 u32TscSeq = uTscSeq + 1;
956 pRefTsc->u32TscSequence = u32TscSeq;
957 pRefTsc->u64TscScale = ((INT64_C(10000) << 32) / u64TscKHz) << 32;
958 pRefTsc->i64TscOffset = 0;
959
960 rc = PGMPhysSimpleWriteGCPhys(pVM, GCPhysTscPage, pRefTsc, sizeof(*pRefTsc));
961 if (RT_SUCCESS(rc))
962 {
963 LogRel(("GIM: HyperV: Enabled TSC page at %#RGp - u64TscScale=%#RX64 u64TscKHz=%#RX64 (%'RU64) Seq=%#RU32\n",
964 GCPhysTscPage, pRefTsc->u64TscScale, u64TscKHz, u64TscKHz, pRefTsc->u32TscSequence));
965
966 pRegion->GCPhysPage = GCPhysTscPage;
967 pRegion->fMapped = true;
968 TMR3CpuTickParavirtEnable(pVM);
969 }
970 else
971 {
972 LogRelFunc(("GIM: HyperV: PGMPhysSimpleWriteGCPhys failed. rc=%Rrc\n", rc));
973 rc = VERR_GIM_OPERATION_FAILED;
974 }
975 RTMemFree(pRefTsc);
976 return rc;
977#endif
978}
979
980
981/**
982 * Disables the Hyper-V TSC page.
983 *
984 * @returns VBox status code.
985 * @param pVM The cross context VM structure.
986 */
987VMMR3_INT_DECL(int) gimR3HvDisableTscPage(PVM pVM)
988{
989 PGIMHV pHv = &pVM->gim.s.u.Hv;
990 PGIMMMIO2REGION pRegion = &pHv->aMmio2Regions[GIM_HV_REF_TSC_PAGE_REGION_IDX];
991 if (pRegion->fMapped)
992 {
993#if 0
994 GIMR3Mmio2Unmap(pVM, pRegion);
995 Assert(!pRegion->fMapped);
996#else
997 pRegion->fMapped = false;
998#endif
999 LogRel(("GIM: HyperV: Disabled TSC-page\n"));
1000
1001 TMR3CpuTickParavirtDisable(pVM);
1002 return VINF_SUCCESS;
1003 }
1004 return VERR_GIM_PVTSC_NOT_ENABLED;
1005}
1006
1007
1008/**
1009 * Disables the Hyper-V Hypercall page.
1010 *
1011 * @returns VBox status code.
1012 */
1013VMMR3_INT_DECL(int) gimR3HvDisableHypercallPage(PVM pVM)
1014{
1015 PGIMHV pHv = &pVM->gim.s.u.Hv;
1016 PGIMMMIO2REGION pRegion = &pHv->aMmio2Regions[GIM_HV_HYPERCALL_PAGE_REGION_IDX];
1017 if (pRegion->fMapped)
1018 {
1019#if 0
1020 GIMR3Mmio2Unmap(pVM, pRegion);
1021 Assert(!pRegion->fMapped);
1022#else
1023 pRegion->fMapped = false;
1024#endif
1025 LogRel(("GIM: HyperV: Disabled Hypercall-page\n"));
1026 return VINF_SUCCESS;
1027 }
1028 return VERR_GIM_HYPERCALLS_NOT_ENABLED;
1029}
1030
1031
1032/**
1033 * Enables the Hyper-V Hypercall page.
1034 *
1035 * @returns VBox status code.
1036 * @param pVM The cross context VM structure.
1037 * @param GCPhysHypercallPage Where to map the hypercall page.
1038 */
1039VMMR3_INT_DECL(int) gimR3HvEnableHypercallPage(PVM pVM, RTGCPHYS GCPhysHypercallPage)
1040{
1041 PPDMDEVINSR3 pDevIns = pVM->gim.s.pDevInsR3;
1042 PGIMMMIO2REGION pRegion = &pVM->gim.s.u.Hv.aMmio2Regions[GIM_HV_HYPERCALL_PAGE_REGION_IDX];
1043 AssertPtrReturn(pDevIns, VERR_GIM_DEVICE_NOT_REGISTERED);
1044
1045 if (pRegion->fMapped)
1046 {
1047 /*
1048 * Is it already enabled at the given guest-address?
1049 */
1050 if (pRegion->GCPhysPage == GCPhysHypercallPage)
1051 return VINF_SUCCESS;
1052
1053 /*
1054 * If it's mapped at a different address, unmap the previous address.
1055 */
1056 int rc2 = gimR3HvDisableHypercallPage(pVM);
1057 AssertRC(rc2);
1058 }
1059
1060 /*
1061 * Map the hypercall-page at the specified address.
1062 */
1063 Assert(!pRegion->fMapped);
1064
1065 /** @todo this is buggy when large pages are used due to a PGM limitation, see
1066 * @bugref{7532}. Instead of the overlay style mapping, we just
1067 * rewrite guest memory directly. */
1068#if 0
1069 int rc = GIMR3Mmio2Map(pVM, pRegion, GCPhysHypercallPage);
1070 if (RT_SUCCESS(rc))
1071 {
1072 Assert(pRegion->GCPhysPage == GCPhysHypercallPage);
1073
1074 /*
1075 * Patch the hypercall-page.
1076 */
1077 size_t cbWritten = 0;
1078 rc = VMMPatchHypercall(pVM, pRegion->pvPageR3, PAGE_SIZE, &cbWritten);
1079 if ( RT_SUCCESS(rc)
1080 && cbWritten < PAGE_SIZE)
1081 {
1082 uint8_t *pbLast = (uint8_t *)pRegion->pvPageR3 + cbWritten;
1083 *pbLast = 0xc3; /* RET */
1084
1085 /*
1086 * Notify VMM that hypercalls are now enabled for all VCPUs.
1087 */
1088 for (VMCPUID i = 0; i < pVM->cCpus; i++)
1089 VMMHypercallsEnable(&pVM->aCpus[i]);
1090
1091 LogRel(("GIM: HyperV: Enabled hypercall page at %#RGp\n", GCPhysHypercallPage));
1092 return VINF_SUCCESS;
1093 }
1094 else
1095 {
1096 if (rc == VINF_SUCCESS)
1097 rc = VERR_GIM_OPERATION_FAILED;
1098 LogRel(("GIM: HyperV: VMMPatchHypercall failed. rc=%Rrc cbWritten=%u\n", rc, cbWritten));
1099 }
1100
1101 GIMR3Mmio2Unmap(pVM, pRegion);
1102 }
1103
1104 LogRel(("GIM: HyperV: GIMR3Mmio2Map failed. rc=%Rrc\n", rc));
1105 return rc;
1106#else
1107 AssertReturn(pRegion->cbRegion == PAGE_SIZE, VERR_GIM_IPE_3);
1108 void *pvHypercallPage = RTMemAllocZ(PAGE_SIZE);
1109 if (RT_UNLIKELY(!pvHypercallPage))
1110 {
1111 LogRelFunc(("Failed to alloc %u bytes\n", PAGE_SIZE));
1112 return VERR_NO_MEMORY;
1113 }
1114
1115 /*
1116 * Patch the hypercall-page.
1117 */
1118 size_t cbWritten = 0;
1119 int rc = VMMPatchHypercall(pVM, pvHypercallPage, PAGE_SIZE, &cbWritten);
1120 if ( RT_SUCCESS(rc)
1121 && cbWritten < PAGE_SIZE)
1122 {
1123 uint8_t *pbLast = (uint8_t *)pvHypercallPage + cbWritten;
1124 *pbLast = 0xc3; /* RET */
1125
1126 rc = PGMPhysSimpleWriteGCPhys(pVM, GCPhysHypercallPage, pvHypercallPage, PAGE_SIZE);
1127 if (RT_SUCCESS(rc))
1128 {
1129 pRegion->GCPhysPage = GCPhysHypercallPage;
1130 pRegion->fMapped = true;
1131 LogRel(("GIM: HyperV: Enabled hypercall page at %#RGp\n", GCPhysHypercallPage));
1132 }
1133 else
1134 LogRel(("GIM: HyperV: PGMPhysSimpleWriteGCPhys failed during hypercall page setup. rc=%Rrc\n", rc));
1135 }
1136 else
1137 {
1138 if (rc == VINF_SUCCESS)
1139 rc = VERR_GIM_OPERATION_FAILED;
1140 LogRel(("GIM: HyperV: VMMPatchHypercall failed. rc=%Rrc cbWritten=%u\n", rc, cbWritten));
1141 }
1142
1143 RTMemFree(pvHypercallPage);
1144 return rc;
1145#endif
1146}
1147
1148
1149/**
1150 * Initializes Hyper-V guest hypercall support.
1151 *
1152 * @returns VBox status code.
1153 * @param pVM The cross context VM structure.
1154 */
1155static int gimR3HvInitHypercallSupport(PVM pVM)
1156{
1157 int rc = VINF_SUCCESS;
1158 PGIMHV pHv = &pVM->gim.s.u.Hv;
1159 pHv->pbHypercallIn = (uint8_t *)RTMemAllocZ(GIM_HV_PAGE_SIZE);
1160 if (RT_LIKELY(pHv->pbHypercallIn))
1161 {
1162 pHv->pbHypercallOut = (uint8_t *)RTMemAllocZ(GIM_HV_PAGE_SIZE);
1163 if (RT_LIKELY(pHv->pbHypercallOut))
1164 return VINF_SUCCESS;
1165 RTMemFree(pHv->pbHypercallIn);
1166 }
1167 return VERR_NO_MEMORY;
1168}
1169
1170
1171/**
1172 * Terminates Hyper-V guest hypercall support.
1173 *
1174 * @param pVM The cross context VM structure.
1175 */
1176static void gimR3HvTermHypercallSupport(PVM pVM)
1177{
1178 PGIMHV pHv = &pVM->gim.s.u.Hv;
1179 RTMemFree(pHv->pbHypercallIn);
1180 pHv->pbHypercallIn = NULL;
1181
1182 RTMemFree(pHv->pbHypercallOut);
1183 pHv->pbHypercallOut = NULL;
1184}
1185
1186
1187/**
1188 * Initializes Hyper-V guest debug support.
1189 *
1190 * @returns VBox status code.
1191 * @param pVM The cross context VM structure.
1192 */
1193static int gimR3HvInitDebugSupport(PVM pVM)
1194{
1195 PGIMHV pHv = &pVM->gim.s.u.Hv;
1196 if ( (pHv->uPartFlags & GIM_HV_PART_FLAGS_DEBUGGING)
1197 || pHv->fIsInterfaceVs)
1198 {
1199 pHv->fDbgEnabled = true;
1200 pHv->pvDbgBuffer = RTMemAllocZ(PAGE_SIZE);
1201 if (!pHv->pvDbgBuffer)
1202 return VERR_NO_MEMORY;
1203 }
1204 return VINF_SUCCESS;
1205}
1206
1207
1208/**
1209 * Terminates Hyper-V guest debug support.
1210 *
1211 * @param pVM The cross context VM structure.
1212 */
1213static void gimR3HvTermDebugSupport(PVM pVM)
1214{
1215 PGIMHV pHv = &pVM->gim.s.u.Hv;
1216 if (pHv->pvDbgBuffer)
1217 {
1218 RTMemFree(pHv->pvDbgBuffer);
1219 pHv->pvDbgBuffer = NULL;
1220 }
1221}
1222
1223
1224/**
1225 * Reads data from a debugger connection, asynchronous.
1226 *
1227 * @returns VBox status code.
1228 * @param pVM The cross context VM structure.
1229 * @param pvBuf Where to read the data.
1230 * @param cbBuf Size of the read buffer @a pvBuf, must be >= @a cbRead.
1231 * @param cbRead Number of bytes to read.
1232 * @param pcbRead Where to store how many bytes were really read.
1233 * @param cMsTimeout Timeout of the read operation in milliseconds.
1234 * @param fUdpPkt Whether the debug data returned in @a pvBuf needs to be
1235 * encapsulated in a UDP frame.
1236 *
1237 * @thread EMT.
1238 */
1239VMMR3_INT_DECL(int) gimR3HvDebugRead(PVM pVM, void *pvBuf, uint32_t cbBuf, uint32_t cbRead, uint32_t *pcbRead,
1240 uint32_t cMsTimeout, bool fUdpPkt)
1241{
1242 NOREF(cMsTimeout); /** @todo implement timeout. */
1243 AssertCompile(sizeof(size_t) >= sizeof(uint32_t));
1244 AssertReturn(cbBuf >= cbRead, VERR_INVALID_PARAMETER);
1245
1246 int rc;
1247 if (!fUdpPkt)
1248 {
1249 /*
1250 * Read the raw debug data.
1251 */
1252 size_t cbReallyRead = cbRead;
1253 rc = GIMR3DebugRead(pVM, pvBuf, &cbReallyRead, gimR3HvDebugBufReadCompleted);
1254 *pcbRead = (uint32_t)cbReallyRead;
1255 }
1256 else
1257 {
1258 /*
1259 * Guest requires UDP encapsulated frames.
1260 */
1261 PGIMHV pHv = &pVM->gim.s.u.Hv;
1262 rc = VERR_GIM_IPE_1;
1263 switch (pHv->enmDbgReply)
1264 {
1265 case GIMHVDEBUGREPLY_UDP:
1266 {
1267 size_t cbReallyRead = cbRead;
1268 rc = GIMR3DebugRead(pVM, pvBuf, &cbReallyRead, gimR3HvDebugBufReadCompleted);
1269 if ( RT_SUCCESS(rc)
1270 && cbReallyRead > 0)
1271 {
1272 uint8_t abFrame[sizeof(RTNETETHERHDR) + RTNETIPV4_MIN_LEN + sizeof(RTNETUDP)];
1273 if (cbReallyRead + sizeof(abFrame) <= cbBuf)
1274 {
1275 /*
1276 * Windows guests pumps ethernet frames over the Hyper-V debug connection as
1277 * explained in gimR3HvHypercallPostDebugData(). Here, we reconstruct the packet
1278 * with the guest's self-chosen IP ARP address we saved in pHv->DbgGuestAddr.
1279 *
1280 * Note! We really need to pass the minimum IPv4 header length. The Windows 10 guest
1281 * is -not- happy if we include the IPv4 options field, i.e. using sizeof(RTNETIPV4)
1282 * instead of RTNETIPV4_MIN_LEN.
1283 */
1284 RT_ZERO(abFrame);
1285 PRTNETETHERHDR pEthHdr = (PRTNETETHERHDR)&abFrame[0];
1286 PRTNETIPV4 pIpHdr = (PRTNETIPV4) (pEthHdr + 1);
1287 PRTNETUDP pUdpHdr = (PRTNETUDP) ((uint8_t *)pIpHdr + RTNETIPV4_MIN_LEN);
1288
1289 /* Ethernet */
1290 pEthHdr->EtherType = RT_H2N_U16_C(RTNET_ETHERTYPE_IPV4);
1291 /* IPv4 */
1292 pIpHdr->ip_v = 4;
1293 pIpHdr->ip_hl = RTNETIPV4_MIN_LEN / sizeof(uint32_t);
1294 pIpHdr->ip_tos = 0;
1295 pIpHdr->ip_len = RT_H2N_U16((uint16_t)cbReallyRead + sizeof(RTNETUDP) + RTNETIPV4_MIN_LEN);
1296 pIpHdr->ip_id = 0;
1297 pIpHdr->ip_off = 0;
1298 pIpHdr->ip_ttl = 255;
1299 pIpHdr->ip_p = RTNETIPV4_PROT_UDP;
1300 pIpHdr->ip_sum = 0;
1301 pIpHdr->ip_src.u = 0;
1302 pIpHdr->ip_dst.u = pHv->DbgGuestIp4Addr.u;
1303 pIpHdr->ip_sum = RTNetIPv4HdrChecksum(pIpHdr);
1304 /* UDP */
1305 pUdpHdr->uh_dport = pHv->uUdpGuestSrcPort;
1306 pUdpHdr->uh_sport = pHv->uUdpGuestDstPort;
1307 pUdpHdr->uh_ulen = RT_H2N_U16_C((uint16_t)cbReallyRead + sizeof(*pUdpHdr));
1308
1309 /* Make room by moving the payload and prepending the headers. */
1310 uint8_t *pbData = (uint8_t *)pvBuf;
1311 memmove(pbData + sizeof(abFrame), pbData, cbReallyRead);
1312 memcpy(pbData, &abFrame[0], sizeof(abFrame));
1313
1314 /* Update the adjusted sizes. */
1315 cbReallyRead += sizeof(abFrame);
1316 }
1317 else
1318 rc = VERR_BUFFER_UNDERFLOW;
1319 }
1320 *pcbRead = (uint32_t)cbReallyRead;
1321 break;
1322 }
1323
1324 case GIMHVDEBUGREPLY_ARP_REPLY:
1325 {
1326 uint32_t const cbArpReplyPkt = sizeof(g_abArpReply);
1327 if (cbBuf >= cbArpReplyPkt)
1328 {
1329 memcpy(pvBuf, g_abArpReply, cbArpReplyPkt);
1330 rc = VINF_SUCCESS;
1331 *pcbRead = cbArpReplyPkt;
1332 pHv->enmDbgReply = GIMHVDEBUGREPLY_ARP_REPLY_SENT;
1333 }
1334 else
1335 {
1336 rc = VERR_BUFFER_UNDERFLOW;
1337 *pcbRead = 0;
1338 }
1339 break;
1340 }
1341
1342 case GIMHVDEBUGREPLY_DHCP_OFFER:
1343 {
1344 uint32_t const cbDhcpOfferPkt = sizeof(g_abDhcpOffer);
1345 if (cbBuf >= cbDhcpOfferPkt)
1346 {
1347 memcpy(pvBuf, g_abDhcpOffer, cbDhcpOfferPkt);
1348 PRTNETETHERHDR pEthHdr = (PRTNETETHERHDR)pvBuf;
1349 PRTNETIPV4 pIpHdr = (PRTNETIPV4) (pEthHdr + 1);
1350 PRTNETUDP pUdpHdr = (PRTNETUDP) ((uint8_t *)pIpHdr + RTNETIPV4_MIN_LEN);
1351 PRTNETBOOTP pBootpHdr = (PRTNETBOOTP) (pUdpHdr + 1);
1352 pBootpHdr->bp_xid = pHv->uDbgBootpXId;
1353
1354 rc = VINF_SUCCESS;
1355 *pcbRead = cbDhcpOfferPkt;
1356 pHv->enmDbgReply = GIMHVDEBUGREPLY_DHCP_OFFER_SENT;
1357 LogRel(("GIM: HyperV: Debug DHCP offered IP address %RTnaipv4, transaction Id %#x\n", pBootpHdr->bp_yiaddr,
1358 RT_N2H_U32(pHv->uDbgBootpXId)));
1359 }
1360 else
1361 {
1362 rc = VERR_BUFFER_UNDERFLOW;
1363 *pcbRead = 0;
1364 }
1365 break;
1366 }
1367
1368 case GIMHVDEBUGREPLY_DHCP_ACK:
1369 {
1370 uint32_t const cbDhcpAckPkt = sizeof(g_abDhcpAck);
1371 if (cbBuf >= cbDhcpAckPkt)
1372 {
1373 memcpy(pvBuf, g_abDhcpAck, cbDhcpAckPkt);
1374 PRTNETETHERHDR pEthHdr = (PRTNETETHERHDR)pvBuf;
1375 PRTNETIPV4 pIpHdr = (PRTNETIPV4) (pEthHdr + 1);
1376 PRTNETUDP pUdpHdr = (PRTNETUDP) ((uint8_t *)pIpHdr + RTNETIPV4_MIN_LEN);
1377 PRTNETBOOTP pBootpHdr = (PRTNETBOOTP) (pUdpHdr + 1);
1378 pBootpHdr->bp_xid = pHv->uDbgBootpXId;
1379
1380 rc = VINF_SUCCESS;
1381 *pcbRead = cbDhcpAckPkt;
1382 pHv->enmDbgReply = GIMHVDEBUGREPLY_DHCP_ACK_SENT;
1383 LogRel(("GIM: HyperV: Debug DHCP acknowledged IP address %RTnaipv4, transaction Id %#x\n",
1384 pBootpHdr->bp_yiaddr, RT_N2H_U32(pHv->uDbgBootpXId)));
1385 }
1386 else
1387 {
1388 rc = VERR_BUFFER_UNDERFLOW;
1389 *pcbRead = 0;
1390 }
1391 break;
1392 }
1393
1394 case GIMHVDEBUGREPLY_ARP_REPLY_SENT:
1395 case GIMHVDEBUGREPLY_DHCP_OFFER_SENT:
1396 case GIMHVDEBUGREPLY_DHCP_ACK_SENT:
1397 {
1398 rc = VINF_SUCCESS;
1399 *pcbRead = 0;
1400 break;
1401 }
1402
1403 default:
1404 {
1405 AssertMsgFailed(("GIM: HyperV: Invalid/unimplemented debug reply type %u\n", pHv->enmDbgReply));
1406 rc = VERR_INTERNAL_ERROR_2;
1407 }
1408 }
1409 Assert(rc != VERR_GIM_IPE_1);
1410
1411#ifdef DEBUG_ramshankar
1412 if ( rc == VINF_SUCCESS
1413 && *pcbRead > 0)
1414 {
1415 RTSOCKET hSocket;
1416 int rc2 = RTUdpCreateClientSocket("localhost", 52000, NULL, &hSocket);
1417 if (RT_SUCCESS(rc2))
1418 {
1419 size_t cbTmpWrite = *pcbRead;
1420 RTSocketWriteNB(hSocket, pvBuf, *pcbRead, &cbTmpWrite); NOREF(cbTmpWrite);
1421 RTSocketClose(hSocket);
1422 }
1423 }
1424#endif
1425 }
1426
1427 return rc;
1428}
1429
1430
1431/**
1432 * Writes data to the debugger connection, asynchronous.
1433 *
1434 * @returns VBox status code.
1435 * @param pVM The cross context VM structure.
1436 * @param pvData Pointer to the data to be written.
1437 * @param cbWrite Size of the write buffer @a pvData.
1438 * @param pcbWritten Where to store the number of bytes written.
1439 * @param fUdpPkt Whether the debug data in @a pvData is encapsulated in a
1440 * UDP frame.
1441 *
1442 * @thread EMT.
1443 */
1444VMMR3_INT_DECL(int) gimR3HvDebugWrite(PVM pVM, void *pvData, uint32_t cbWrite, uint32_t *pcbWritten, bool fUdpPkt)
1445{
1446 Assert(cbWrite > 0);
1447
1448 PGIMHV pHv = &pVM->gim.s.u.Hv;
1449 bool fIgnorePkt = false;
1450 uint8_t *pbData = (uint8_t *)pvData;
1451 if (fUdpPkt)
1452 {
1453#ifdef DEBUG_ramshankar
1454 RTSOCKET hSocket;
1455 int rc2 = RTUdpCreateClientSocket("localhost", 52000, NULL, &hSocket);
1456 if (RT_SUCCESS(rc2))
1457 {
1458 size_t cbTmpWrite = cbWrite;
1459 RTSocketWriteNB(hSocket, pbData, cbWrite, &cbTmpWrite); NOREF(cbTmpWrite);
1460 RTSocketClose(hSocket);
1461 }
1462#endif
1463 /*
1464 * Windows guests sends us ethernet frames over the Hyper-V debug connection.
1465 * It sends DHCP/ARP queries with zero'd out MAC addresses and requires fudging up the
1466 * packets somewhere.
1467 *
1468 * The Microsoft WinDbg debugger talks UDP and thus only expects the actual debug
1469 * protocol payload.
1470 *
1471 * If the guest is configured with the "nodhcp" option it sends ARP queries with
1472 * a self-chosen IP and after a couple of attempts of receiving no replies, the guest
1473 * picks its own IP address. After this, the guest starts sending the UDP packets
1474 * we require. We thus ignore the initial ARP packets until the guest eventually
1475 * starts talking UDP. Then we can finally feed the UDP payload over the debug
1476 * connection.
1477 *
1478 * When 'kdvm.dll' is the debug transport in the guest (Windows 7), it doesn't bother
1479 * with this DHCP/ARP phase. It starts sending debug data in a UDP frame right away.
1480 */
1481 if (cbWrite > sizeof(RTNETETHERHDR))
1482 {
1483 PCRTNETETHERHDR pEtherHdr = (PCRTNETETHERHDR)pbData;
1484 if (pEtherHdr->EtherType == RT_H2N_U16_C(RTNET_ETHERTYPE_IPV4))
1485 {
1486 if (cbWrite > sizeof(RTNETETHERHDR) + RTNETIPV4_MIN_LEN + RTNETUDP_MIN_LEN)
1487 {
1488 size_t const cbMaxIpHdr = cbWrite - sizeof(RTNETETHERHDR) - sizeof(RTNETUDP) - 1;
1489 size_t const cbMaxIpPkt = cbWrite - sizeof(RTNETETHERHDR);
1490 PCRTNETIPV4 pIp4Hdr = (PCRTNETIPV4)(pbData + sizeof(RTNETETHERHDR));
1491 bool const fValidIp4 = RTNetIPv4IsHdrValid(pIp4Hdr, cbMaxIpHdr, cbMaxIpPkt, false /*fChecksum*/);
1492 if ( fValidIp4
1493 && pIp4Hdr->ip_p == RTNETIPV4_PROT_UDP)
1494 {
1495 uint32_t const cbIpHdr = pIp4Hdr->ip_hl * 4;
1496 uint32_t const cbMaxUdpPkt = cbWrite - sizeof(RTNETETHERHDR) - cbIpHdr;
1497 PCRTNETUDP pUdpHdr = (PCRTNETUDP)((uint8_t *)pIp4Hdr + cbIpHdr);
1498 if ( pUdpHdr->uh_ulen > RT_H2N_U16(sizeof(RTNETUDP))
1499 && pUdpHdr->uh_ulen <= RT_H2N_U16((uint16_t)cbMaxUdpPkt))
1500 {
1501 /*
1502 * Check for DHCP.
1503 */
1504 bool fBuggyPkt = false;
1505 size_t const cbUdpPkt = cbMaxIpPkt - cbIpHdr;
1506 if ( pUdpHdr->uh_dport == RT_N2H_U16_C(RTNETIPV4_PORT_BOOTPS)
1507 && pUdpHdr->uh_sport == RT_N2H_U16_C(RTNETIPV4_PORT_BOOTPC))
1508 {
1509 PCRTNETBOOTP pDhcpPkt = (PCRTNETBOOTP)(pUdpHdr + 1);
1510 uint8_t bMsgType;
1511 if ( cbMaxIpPkt >= cbIpHdr + RTNETUDP_MIN_LEN + RTNETBOOTP_DHCP_MIN_LEN
1512 && RTNetIPv4IsDHCPValid(pUdpHdr, pDhcpPkt, cbUdpPkt - sizeof(*pUdpHdr), &bMsgType))
1513 {
1514 switch (bMsgType)
1515 {
1516 case RTNET_DHCP_MT_DISCOVER:
1517 pHv->enmDbgReply = GIMHVDEBUGREPLY_DHCP_OFFER;
1518 pHv->uDbgBootpXId = pDhcpPkt->bp_xid;
1519 break;
1520 case RTNET_DHCP_MT_REQUEST:
1521 pHv->enmDbgReply = GIMHVDEBUGREPLY_DHCP_ACK;
1522 pHv->uDbgBootpXId = pDhcpPkt->bp_xid;
1523 break;
1524 default:
1525 LogRelMax(5, ("GIM: HyperV: Debug DHCP MsgType %#x not implemented! Packet dropped\n",
1526 bMsgType));
1527 break;
1528 }
1529 fIgnorePkt = true;
1530 }
1531 else if ( pIp4Hdr->ip_src.u == GIMHV_DEBUGCLIENT_IPV4
1532 && pIp4Hdr->ip_dst.u == 0)
1533 {
1534 /*
1535 * Windows 8.1 seems to be sending malformed BOOTP packets at the final stage of the
1536 * debugger sequence. It appears that a previously sent DHCP request buffer wasn't cleared
1537 * in the guest and they re-use it instead of sending a zero destination+source port packet
1538 * as expected below.
1539 *
1540 * We workaround Microsoft's bug here, or at least, I'm classifying it as a bug to
1541 * preserve my own sanity, see @bugref{8006#c54}.
1542 */
1543 fBuggyPkt = true;
1544 }
1545 }
1546
1547 if ( ( !pUdpHdr->uh_dport
1548 && !pUdpHdr->uh_sport)
1549 || fBuggyPkt)
1550 {
1551 /*
1552 * Extract the UDP payload and pass it to the debugger and record the guest IP address.
1553 *
1554 * Hyper-V sends UDP debugger packets with source and destination port as 0 except in the
1555 * aformentioned buggy case. The buggy packet case requires us to remember the ports and
1556 * reply to them, otherwise the guest won't receive the replies we sent with port 0.
1557 */
1558 uint32_t const cbFrameHdr = sizeof(RTNETETHERHDR) + cbIpHdr + sizeof(RTNETUDP);
1559 pbData += cbFrameHdr;
1560 cbWrite -= cbFrameHdr;
1561 pHv->DbgGuestIp4Addr.u = pIp4Hdr->ip_src.u;
1562 pHv->uUdpGuestDstPort = pUdpHdr->uh_dport;
1563 pHv->uUdpGuestSrcPort = pUdpHdr->uh_sport;
1564 pHv->enmDbgReply = GIMHVDEBUGREPLY_UDP;
1565 }
1566 else
1567 {
1568 LogFlow(("GIM: HyperV: Ignoring UDP packet SourcePort=%u DstPort=%u\n", pUdpHdr->uh_sport,
1569 pUdpHdr->uh_dport));
1570 fIgnorePkt = true;
1571 }
1572 }
1573 else
1574 {
1575 LogFlow(("GIM: HyperV: Ignoring malformed UDP packet. cbMaxUdpPkt=%u UdpPkt.len=%u\n", cbMaxUdpPkt,
1576 RT_N2H_U16(pUdpHdr->uh_ulen)));
1577 fIgnorePkt = true;
1578 }
1579 }
1580 else
1581 {
1582 LogFlow(("GIM: HyperV: Ignoring non-IP / non-UDP packet. fValidIp4=%RTbool Proto=%u\n", fValidIp4,
1583 pIp4Hdr->ip_p));
1584 fIgnorePkt = true;
1585 }
1586 }
1587 else
1588 {
1589 LogFlow(("GIM: HyperV: Ignoring IPv4 packet; too short to be valid UDP. cbWrite=%u\n", cbWrite));
1590 fIgnorePkt = true;
1591 }
1592 }
1593 else if (pEtherHdr->EtherType == RT_H2N_U16_C(RTNET_ETHERTYPE_ARP))
1594 {
1595 /*
1596 * Check for targetted ARP query.
1597 */
1598 PCRTNETARPHDR pArpHdr = (PCRTNETARPHDR)(pbData + sizeof(RTNETETHERHDR));
1599 if ( pArpHdr->ar_hlen == sizeof(RTMAC)
1600 && pArpHdr->ar_plen == sizeof(RTNETADDRIPV4)
1601 && pArpHdr->ar_htype == RT_H2N_U16(RTNET_ARP_ETHER)
1602 && pArpHdr->ar_ptype == RT_H2N_U16(RTNET_ETHERTYPE_IPV4))
1603 {
1604 uint16_t uArpOp = pArpHdr->ar_oper;
1605 if (uArpOp == RT_H2N_U16_C(RTNET_ARPOP_REQUEST))
1606 {
1607 PCRTNETARPIPV4 pArpPkt = (PCRTNETARPIPV4)pArpHdr;
1608 bool fGratuitous = pArpPkt->ar_spa.u == pArpPkt->ar_tpa.u;
1609 if ( !fGratuitous
1610 && pArpPkt->ar_spa.u == GIMHV_DEBUGCLIENT_IPV4
1611 && pArpPkt->ar_tpa.u == GIMHV_DEBUGSERVER_IPV4)
1612 {
1613 pHv->enmDbgReply = GIMHVDEBUGREPLY_ARP_REPLY;
1614 }
1615 }
1616 }
1617 fIgnorePkt = true;
1618 }
1619 else
1620 {
1621 LogFlow(("GIM: HyperV: Ignoring non-IP packet. Ethertype=%#x\n", RT_N2H_U16(pEtherHdr->EtherType)));
1622 fIgnorePkt = true;
1623 }
1624 }
1625 }
1626
1627 if (!fIgnorePkt)
1628 {
1629 AssertCompile(sizeof(size_t) >= sizeof(uint32_t));
1630 size_t cbWriteBuf = cbWrite;
1631 int rc = GIMR3DebugWrite(pVM, pbData, &cbWriteBuf);
1632 if ( RT_SUCCESS(rc)
1633 && cbWriteBuf == cbWrite)
1634 *pcbWritten = (uint32_t)cbWriteBuf;
1635 else
1636 *pcbWritten = 0;
1637 }
1638 else
1639 *pcbWritten = cbWrite;
1640
1641 return VINF_SUCCESS;
1642}
1643
1644
1645/**
1646 * Performs the HvPostDebugData hypercall.
1647 *
1648 * @returns VBox status code.
1649 * @param pVM The cross context VM structure.
1650 * @param prcHv Where to store the result of the hypercall operation.
1651 *
1652 * @thread EMT.
1653 */
1654VMMR3_INT_DECL(int) gimR3HvHypercallPostDebugData(PVM pVM, int *prcHv)
1655{
1656 AssertPtr(pVM);
1657 AssertPtr(prcHv);
1658 PGIMHV pHv = &pVM->gim.s.u.Hv;
1659 int rcHv = GIM_HV_STATUS_OPERATION_DENIED;
1660
1661 /*
1662 * Grab the parameters.
1663 */
1664 PGIMHVDEBUGPOSTIN pIn = (PGIMHVDEBUGPOSTIN)pHv->pbHypercallIn;
1665 AssertPtrReturn(pIn, VERR_GIM_IPE_1);
1666 uint32_t cbWrite = pIn->cbWrite;
1667 uint32_t fFlags = pIn->fFlags;
1668 uint8_t *pbData = ((uint8_t *)pIn) + sizeof(PGIMHVDEBUGPOSTIN);
1669
1670 PGIMHVDEBUGPOSTOUT pOut = (PGIMHVDEBUGPOSTOUT)pHv->pbHypercallOut;
1671
1672 /*
1673 * Perform the hypercall.
1674 */
1675#if 0
1676 /* Currently disabled as Windows 10 guest passes us undocumented flags. */
1677 if (fFlags & ~GIM_HV_DEBUG_POST_OPTIONS_MASK))
1678 rcHv = GIM_HV_STATUS_INVALID_PARAMETER;
1679#endif
1680 if (cbWrite > GIM_HV_DEBUG_MAX_DATA_SIZE)
1681 rcHv = GIM_HV_STATUS_INVALID_PARAMETER;
1682 else if (!cbWrite)
1683 {
1684 rcHv = GIM_HV_STATUS_SUCCESS;
1685 pOut->cbPending = 0;
1686 }
1687 else if (cbWrite > 0)
1688 {
1689 uint32_t cbWritten = 0;
1690 int rc2 = gimR3HvDebugWrite(pVM, pbData, cbWrite, &cbWritten, pHv->fIsVendorMsHv /*fUdpPkt*/);
1691 if ( RT_SUCCESS(rc2)
1692 && cbWritten == cbWrite)
1693 {
1694 pOut->cbPending = 0;
1695 rcHv = GIM_HV_STATUS_SUCCESS;
1696 }
1697 else
1698 rcHv = GIM_HV_STATUS_INSUFFICIENT_BUFFER;
1699 }
1700
1701 /*
1702 * Update the guest memory with result.
1703 */
1704 int rc = PGMPhysSimpleWriteGCPhys(pVM, pHv->GCPhysHypercallOut, pHv->pbHypercallOut, sizeof(GIMHVDEBUGPOSTOUT));
1705 if (RT_FAILURE(rc))
1706 {
1707 LogRelMax(10, ("GIM: HyperV: HvPostDebugData failed to update guest memory. rc=%Rrc\n", rc));
1708 rc = VERR_GIM_HYPERCALL_MEMORY_WRITE_FAILED;
1709 }
1710
1711 *prcHv = rcHv;
1712 return rc;
1713}
1714
1715
1716/**
1717 * Performs the HvRetrieveDebugData hypercall.
1718 *
1719 * @returns VBox status code.
1720 * @param pVM The cross context VM structure.
1721 * @param prcHv Where to store the result of the hypercall operation.
1722 *
1723 * @thread EMT.
1724 */
1725VMMR3_INT_DECL(int) gimR3HvHypercallRetrieveDebugData(PVM pVM, int *prcHv)
1726{
1727 AssertPtr(pVM);
1728 AssertPtr(prcHv);
1729 PGIMHV pHv = &pVM->gim.s.u.Hv;
1730 int rcHv = GIM_HV_STATUS_OPERATION_DENIED;
1731
1732 /*
1733 * Grab the parameters.
1734 */
1735 PGIMHVDEBUGRETRIEVEIN pIn = (PGIMHVDEBUGRETRIEVEIN)pHv->pbHypercallIn;
1736 AssertPtrReturn(pIn, VERR_GIM_IPE_1);
1737 uint32_t cbRead = pIn->cbRead;
1738 uint32_t fFlags = pIn->fFlags;
1739 uint64_t uTimeout = pIn->u64Timeout;
1740 uint32_t cMsTimeout = (fFlags & GIM_HV_DEBUG_RETREIVE_LOOP) ? (uTimeout * 100) / RT_NS_1MS_64 : 0;
1741
1742 PGIMHVDEBUGRETRIEVEOUT pOut = (PGIMHVDEBUGRETRIEVEOUT)pHv->pbHypercallOut;
1743 AssertPtrReturn(pOut, VERR_GIM_IPE_2);
1744 uint32_t *pcbReallyRead = &pOut->cbRead;
1745 uint32_t *pcbRemainingRead = &pOut->cbRemaining;
1746 void *pvData = ((uint8_t *)pOut) + sizeof(GIMHVDEBUGRETRIEVEOUT);
1747
1748 /*
1749 * Perform the hypercall.
1750 */
1751 *pcbReallyRead = 0;
1752 *pcbRemainingRead = cbRead;
1753#if 0
1754 /* Currently disabled as Windows 10 guest passes us undocumented flags. */
1755 if (fFlags & ~GIM_HV_DEBUG_RETREIVE_OPTIONS_MASK)
1756 rcHv = GIM_HV_STATUS_INVALID_PARAMETER;
1757#endif
1758 if (cbRead > GIM_HV_DEBUG_MAX_DATA_SIZE)
1759 rcHv = GIM_HV_STATUS_INVALID_PARAMETER;
1760 else if (fFlags & GIM_HV_DEBUG_RETREIVE_TEST_ACTIVITY)
1761 rcHv = GIM_HV_STATUS_SUCCESS; /** @todo implement this. */
1762 else if (!cbRead)
1763 rcHv = GIM_HV_STATUS_SUCCESS;
1764 else if (cbRead > 0)
1765 {
1766 int rc2 = gimR3HvDebugRead(pVM, pvData, GIM_HV_PAGE_SIZE, cbRead, pcbReallyRead, cMsTimeout,
1767 pHv->fIsVendorMsHv /*fUdpPkt*/);
1768 Assert(*pcbReallyRead <= cbRead);
1769 if ( RT_SUCCESS(rc2)
1770 && *pcbReallyRead > 0)
1771 {
1772 *pcbRemainingRead = cbRead - *pcbReallyRead;
1773 rcHv = GIM_HV_STATUS_SUCCESS;
1774 }
1775 else
1776 rcHv = GIM_HV_STATUS_NO_DATA;
1777 }
1778
1779 /*
1780 * Update the guest memory with result.
1781 */
1782 int rc = PGMPhysSimpleWriteGCPhys(pVM, pHv->GCPhysHypercallOut, pHv->pbHypercallOut,
1783 sizeof(GIMHVDEBUGRETRIEVEOUT) + *pcbReallyRead);
1784 if (RT_FAILURE(rc))
1785 {
1786 LogRelMax(10, ("GIM: HyperV: HvRetrieveDebugData failed to update guest memory. rc=%Rrc\n", rc));
1787 rc = VERR_GIM_HYPERCALL_MEMORY_WRITE_FAILED;
1788 }
1789
1790 *prcHv = rcHv;
1791 return rc;
1792}
1793
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