VirtualBox

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

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

gimR3HvInit: Check VendorID length or we'll pick up random stack bits from the stack. Marked confusing RTStNCmp use.

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