VirtualBox

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

Last change on this file since 80239 was 80191, checked in by vboxsync, 5 years ago

VMM/r3: Refactored VMCPU enumeration in preparation that aCpus will be replaced with a pointer array. Removed two raw-mode offset members from the CPUM and CPUMCPU sub-structures. bugref:9217 bugref:9517

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