VirtualBox

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

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

(C) 2016

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