VirtualBox

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

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

CPUM,APIC: Per-CPU APIC CPUID feature bit and MSR_IA32_APICBASE GP mask adjustments.

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

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