VirtualBox

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

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

VMM/GIM: Saved state bump for MSR based debugging support.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette