VirtualBox

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

Last change on this file since 72208 was 72193, checked in by vboxsync, 7 years ago

VMM/GIM/HyperV: Include the debug UDP source and destination ports in the saved-state as the state may be obtained during
a debug read/write sequence. Bumps Hyper-V saved-state version.

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