VirtualBox

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

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

VMM/GIM: spaces.

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