VirtualBox

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

Last change on this file since 84044 was 82968, checked in by vboxsync, 4 years ago

Copyright year updates by scm.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use