VirtualBox

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

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

GIM/Hv: Need to restore hypercall instruction enable state on load. (KVM always enables hypercall instructions, so nothing to do there.) bugref:9044

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 85.8 KB
Line 
1/* $Id: GIMHv.cpp 72460 2018-06-06 11:16:12Z 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 * Hyper-V load-done callback.
1032 *
1033 * @returns VBox status code.
1034 * @param pVM The cross context VM structure.
1035 * @param pSSM The saved state handle.
1036 */
1037VMMR3_INT_DECL(int) gimR3HvLoadDone(PVM pVM, PSSMHANDLE pSSM)
1038{
1039 if (RT_SUCCESS(SSMR3HandleGetStatus(pSSM)))
1040 {
1041 /*
1042 * Update EM on whether MSR_GIM_HV_GUEST_OS_ID allows hypercall instructions.
1043 */
1044 if (pVM->gim.s.u.Hv.u64GuestOsIdMsr)
1045 for (VMCPUID i = 0; i < pVM->cCpus; i++)
1046 VMMHypercallsEnable(&pVM->aCpus[i]);
1047 else
1048 for (VMCPUID i = 0; i < pVM->cCpus; i++)
1049 VMMHypercallsDisable(&pVM->aCpus[i]);
1050 }
1051 return VINF_SUCCESS;
1052}
1053
1054
1055/**
1056 * Enables the Hyper-V APIC-assist page.
1057 *
1058 * @returns VBox status code.
1059 * @param pVCpu The cross context virtual CPU structure.
1060 * @param GCPhysApicAssistPage Where to map the APIC-assist page.
1061 */
1062VMMR3_INT_DECL(int) gimR3HvEnableApicAssistPage(PVMCPU pVCpu, RTGCPHYS GCPhysApicAssistPage)
1063{
1064 PVM pVM = pVCpu->CTX_SUFF(pVM);
1065 PPDMDEVINSR3 pDevIns = pVM->gim.s.pDevInsR3;
1066 AssertPtrReturn(pDevIns, VERR_GIM_DEVICE_NOT_REGISTERED);
1067
1068 /*
1069 * Map the APIC-assist-page at the specified address.
1070 */
1071 /** @todo this is buggy when large pages are used due to a PGM limitation, see
1072 * @bugref{7532}. Instead of the overlay style mapping, we just
1073 * rewrite guest memory directly. */
1074 size_t const cbApicAssistPage = PAGE_SIZE;
1075 void *pvApicAssist = RTMemAllocZ(cbApicAssistPage);
1076 if (RT_LIKELY(pvApicAssist))
1077 {
1078 int rc = PGMPhysSimpleWriteGCPhys(pVM, GCPhysApicAssistPage, pvApicAssist, cbApicAssistPage);
1079 if (RT_SUCCESS(rc))
1080 {
1081 /** @todo Inform APIC. */
1082 LogRel(("GIM%u: HyperV: Enabled APIC-assist page at %#RGp\n", pVCpu->idCpu, GCPhysApicAssistPage));
1083 }
1084 else
1085 {
1086 LogRelFunc(("GIM%u: HyperV: PGMPhysSimpleWriteGCPhys failed. rc=%Rrc\n", pVCpu->idCpu, rc));
1087 rc = VERR_GIM_OPERATION_FAILED;
1088 }
1089
1090 RTMemFree(pvApicAssist);
1091 return rc;
1092 }
1093
1094 LogRelFunc(("GIM%u: HyperV: Failed to alloc %u bytes\n", pVCpu->idCpu, cbApicAssistPage));
1095 return VERR_NO_MEMORY;
1096}
1097
1098
1099/**
1100 * Disables the Hyper-V APIC-assist page.
1101 *
1102 * @returns VBox status code.
1103 * @param pVCpu The cross context virtual CPU structure.
1104 */
1105VMMR3_INT_DECL(int) gimR3HvDisableApicAssistPage(PVMCPU pVCpu)
1106{
1107 LogRel(("GIM%u: HyperV: Disabled APIC-assist page\n", pVCpu->idCpu));
1108 /** @todo inform APIC */
1109 return VINF_SUCCESS;
1110}
1111
1112
1113/**
1114 * Hyper-V synthetic timer callback.
1115 *
1116 * @param pVM The cross context VM structure.
1117 * @param pTimer Pointer to timer.
1118 * @param pvUser Pointer to the synthetic timer.
1119 */
1120static DECLCALLBACK(void) gimR3HvTimerCallback(PVM pVM, PTMTIMER pTimer, void *pvUser)
1121{
1122 PGIMHVSTIMER pHvStimer = (PGIMHVSTIMER)pvUser;
1123 Assert(pHvStimer);
1124 Assert(TMTimerIsLockOwner(pTimer)); RT_NOREF(pTimer);
1125 Assert(pHvStimer->idCpu < pVM->cCpus);
1126
1127 PVMCPU pVCpu = &pVM->aCpus[pHvStimer->idCpu];
1128 PGIMHVCPU pHvCpu = &pVCpu->gim.s.u.HvCpu;
1129 Assert(pHvStimer->idxStimer < RT_ELEMENTS(pHvCpu->aStatStimerFired));
1130
1131 STAM_COUNTER_INC(&pHvCpu->aStatStimerFired[pHvStimer->idxStimer]);
1132
1133 uint64_t const uStimerConfig = pHvStimer->uStimerConfigMsr;
1134 uint16_t const idxSint = MSR_GIM_HV_STIMER_GET_SINTX(uStimerConfig);
1135 if (RT_LIKELY(idxSint < RT_ELEMENTS(pHvCpu->auSintMsrs)))
1136 {
1137 uint64_t const uSint = pHvCpu->auSintMsrs[idxSint];
1138 if (!MSR_GIM_HV_SINT_IS_MASKED(uSint))
1139 {
1140 uint8_t const uVector = MSR_GIM_HV_SINT_GET_VECTOR(uSint);
1141 bool const fAutoEoi = MSR_GIM_HV_SINT_IS_AUTOEOI(uSint);
1142 APICHvSendInterrupt(pVCpu, uVector, fAutoEoi, XAPICTRIGGERMODE_EDGE);
1143 }
1144 }
1145
1146 /* Re-arm the timer if it's periodic. */
1147 if (MSR_GIM_HV_STIMER_IS_PERIODIC(uStimerConfig))
1148 gimHvStartStimer(pVCpu, pHvStimer);
1149}
1150
1151
1152/**
1153 * Enables the Hyper-V SIEF page.
1154 *
1155 * @returns VBox status code.
1156 * @param pVCpu The cross context virtual CPU structure.
1157 * @param GCPhysSiefPage Where to map the SIEF page.
1158 */
1159VMMR3_INT_DECL(int) gimR3HvEnableSiefPage(PVMCPU pVCpu, RTGCPHYS GCPhysSiefPage)
1160{
1161 PVM pVM = pVCpu->CTX_SUFF(pVM);
1162 PPDMDEVINSR3 pDevIns = pVM->gim.s.pDevInsR3;
1163 AssertPtrReturn(pDevIns, VERR_GIM_DEVICE_NOT_REGISTERED);
1164
1165 /*
1166 * Map the SIEF page at the specified address.
1167 */
1168 /** @todo this is buggy when large pages are used due to a PGM limitation, see
1169 * @bugref{7532}. Instead of the overlay style mapping, we just
1170 * rewrite guest memory directly. */
1171 size_t const cbSiefPage = PAGE_SIZE;
1172 void *pvSiefPage = RTMemAllocZ(cbSiefPage);
1173 if (RT_LIKELY(pvSiefPage))
1174 {
1175 int rc = PGMPhysSimpleWriteGCPhys(pVM, GCPhysSiefPage, pvSiefPage, cbSiefPage);
1176 if (RT_SUCCESS(rc))
1177 {
1178 /** @todo SIEF setup. */
1179 LogRel(("GIM%u: HyperV: Enabled SIEF page at %#RGp\n", pVCpu->idCpu, GCPhysSiefPage));
1180 }
1181 else
1182 {
1183 LogRelFunc(("GIM%u: HyperV: PGMPhysSimpleWriteGCPhys failed. rc=%Rrc\n", pVCpu->idCpu, rc));
1184 rc = VERR_GIM_OPERATION_FAILED;
1185 }
1186
1187 RTMemFree(pvSiefPage);
1188 return rc;
1189 }
1190
1191 LogRelFunc(("GIM%u: HyperV: Failed to alloc %u bytes\n", pVCpu->idCpu, cbSiefPage));
1192 return VERR_NO_MEMORY;
1193}
1194
1195
1196/**
1197 * Disables the Hyper-V SIEF page.
1198 *
1199 * @returns VBox status code.
1200 * @param pVCpu The cross context virtual CPU structure.
1201 */
1202VMMR3_INT_DECL(int) gimR3HvDisableSiefPage(PVMCPU pVCpu)
1203{
1204 LogRel(("GIM%u: HyperV: Disabled APIC-assist page\n", pVCpu->idCpu));
1205 /** @todo SIEF teardown. */
1206 return VINF_SUCCESS;
1207}
1208
1209
1210/**
1211 * Enables the Hyper-V TSC page.
1212 *
1213 * @returns VBox status code.
1214 * @param pVM The cross context VM structure.
1215 * @param GCPhysTscPage Where to map the TSC page.
1216 * @param fUseThisTscSeq Whether to set the TSC sequence number to the one
1217 * specified in @a uTscSeq.
1218 * @param uTscSeq The TSC sequence value to use. Ignored if
1219 * @a fUseThisTscSeq is false.
1220 */
1221VMMR3_INT_DECL(int) gimR3HvEnableTscPage(PVM pVM, RTGCPHYS GCPhysTscPage, bool fUseThisTscSeq, uint32_t uTscSeq)
1222{
1223 PPDMDEVINSR3 pDevIns = pVM->gim.s.pDevInsR3;
1224 PGIMMMIO2REGION pRegion = &pVM->gim.s.u.Hv.aMmio2Regions[GIM_HV_REF_TSC_PAGE_REGION_IDX];
1225 AssertPtrReturn(pDevIns, VERR_GIM_DEVICE_NOT_REGISTERED);
1226
1227 int rc;
1228 if (pRegion->fMapped)
1229 {
1230 /*
1231 * Is it already enabled at the given guest-address?
1232 */
1233 if (pRegion->GCPhysPage == GCPhysTscPage)
1234 return VINF_SUCCESS;
1235
1236 /*
1237 * If it's mapped at a different address, unmap the previous address.
1238 */
1239 rc = gimR3HvDisableTscPage(pVM);
1240 AssertRC(rc);
1241 }
1242
1243 /*
1244 * Map the TSC-page at the specified address.
1245 */
1246 Assert(!pRegion->fMapped);
1247
1248 /** @todo this is buggy when large pages are used due to a PGM limitation, see
1249 * @bugref{7532}. Instead of the overlay style mapping, we just
1250 * rewrite guest memory directly. */
1251#if 0
1252 rc = gimR3Mmio2Map(pVM, pRegion, GCPhysTscPage);
1253 if (RT_SUCCESS(rc))
1254 {
1255 Assert(pRegion->GCPhysPage == GCPhysTscPage);
1256
1257 /*
1258 * Update the TSC scale. Windows guests expect a non-zero TSC sequence, otherwise
1259 * they fallback to using the reference count MSR which is not ideal in terms of VM-exits.
1260 *
1261 * Also, Hyper-V normalizes the time in 10 MHz, see:
1262 * http://technet.microsoft.com/it-it/sysinternals/dn553408%28v=vs.110%29
1263 */
1264 PGIMHVREFTSC pRefTsc = (PGIMHVREFTSC)pRegion->pvPageR3;
1265 Assert(pRefTsc);
1266
1267 PGIMHV pHv = &pVM->gim.s.u.Hv;
1268 uint64_t const u64TscKHz = pHv->cTscTicksPerSecond / UINT64_C(1000);
1269 uint32_t u32TscSeq = 1;
1270 if ( fUseThisTscSeq
1271 && uTscSeq < UINT32_C(0xfffffffe))
1272 u32TscSeq = uTscSeq + 1;
1273 pRefTsc->u32TscSequence = u32TscSeq;
1274 pRefTsc->u64TscScale = ((INT64_C(10000) << 32) / u64TscKHz) << 32;
1275 pRefTsc->i64TscOffset = 0;
1276
1277 LogRel(("GIM: HyperV: Enabled TSC page at %#RGp - u64TscScale=%#RX64 u64TscKHz=%#RX64 (%'RU64) Seq=%#RU32\n",
1278 GCPhysTscPage, pRefTsc->u64TscScale, u64TscKHz, u64TscKHz, pRefTsc->u32TscSequence));
1279
1280 TMR3CpuTickParavirtEnable(pVM);
1281 return VINF_SUCCESS;
1282 }
1283 else
1284 LogRelFunc(("gimR3Mmio2Map failed. rc=%Rrc\n", rc));
1285 return VERR_GIM_OPERATION_FAILED;
1286#else
1287 AssertReturn(pRegion->cbRegion == PAGE_SIZE, VERR_GIM_IPE_2);
1288 PGIMHVREFTSC pRefTsc = (PGIMHVREFTSC)RTMemAllocZ(PAGE_SIZE);
1289 if (RT_UNLIKELY(!pRefTsc))
1290 {
1291 LogRelFunc(("Failed to alloc %u bytes\n", PAGE_SIZE));
1292 return VERR_NO_MEMORY;
1293 }
1294
1295 PGIMHV pHv = &pVM->gim.s.u.Hv;
1296 uint64_t const u64TscKHz = pHv->cTscTicksPerSecond / UINT64_C(1000);
1297 uint32_t u32TscSeq = 1;
1298 if ( fUseThisTscSeq
1299 && uTscSeq < UINT32_C(0xfffffffe))
1300 u32TscSeq = uTscSeq + 1;
1301 pRefTsc->u32TscSequence = u32TscSeq;
1302 pRefTsc->u64TscScale = ((INT64_C(10000) << 32) / u64TscKHz) << 32;
1303 pRefTsc->i64TscOffset = 0;
1304
1305 rc = PGMPhysSimpleWriteGCPhys(pVM, GCPhysTscPage, pRefTsc, sizeof(*pRefTsc));
1306 if (RT_SUCCESS(rc))
1307 {
1308 LogRel(("GIM: HyperV: Enabled TSC page at %#RGp - u64TscScale=%#RX64 u64TscKHz=%#RX64 (%'RU64) Seq=%#RU32\n",
1309 GCPhysTscPage, pRefTsc->u64TscScale, u64TscKHz, u64TscKHz, pRefTsc->u32TscSequence));
1310
1311 pRegion->GCPhysPage = GCPhysTscPage;
1312 pRegion->fMapped = true;
1313 TMR3CpuTickParavirtEnable(pVM);
1314 }
1315 else
1316 {
1317 LogRelFunc(("GIM: HyperV: PGMPhysSimpleWriteGCPhys failed. rc=%Rrc\n", rc));
1318 rc = VERR_GIM_OPERATION_FAILED;
1319 }
1320 RTMemFree(pRefTsc);
1321 return rc;
1322#endif
1323}
1324
1325
1326/**
1327 * Enables the Hyper-V SIM page.
1328 *
1329 * @returns VBox status code.
1330 * @param pVCpu The cross context virtual CPU structure.
1331 * @param GCPhysSimPage Where to map the SIM page.
1332 */
1333VMMR3_INT_DECL(int) gimR3HvEnableSimPage(PVMCPU pVCpu, RTGCPHYS GCPhysSimPage)
1334{
1335 PVM pVM = pVCpu->CTX_SUFF(pVM);
1336 PPDMDEVINSR3 pDevIns = pVM->gim.s.pDevInsR3;
1337 AssertPtrReturn(pDevIns, VERR_GIM_DEVICE_NOT_REGISTERED);
1338
1339 /*
1340 * Map the SIMP page at the specified address.
1341 */
1342 /** @todo this is buggy when large pages are used due to a PGM limitation, see
1343 * @bugref{7532}. Instead of the overlay style mapping, we just
1344 * rewrite guest memory directly. */
1345 size_t const cbSimPage = PAGE_SIZE;
1346 void *pvSimPage = RTMemAllocZ(cbSimPage);
1347 if (RT_LIKELY(pvSimPage))
1348 {
1349 int rc = PGMPhysSimpleWriteGCPhys(pVM, GCPhysSimPage, pvSimPage, cbSimPage);
1350 if (RT_SUCCESS(rc))
1351 {
1352 /** @todo SIM setup. */
1353 LogRel(("GIM%u: HyperV: Enabled SIM page at %#RGp\n", pVCpu->idCpu, GCPhysSimPage));
1354 }
1355 else
1356 {
1357 LogRelFunc(("GIM%u: HyperV: PGMPhysSimpleWriteGCPhys failed. rc=%Rrc\n", pVCpu->idCpu, rc));
1358 rc = VERR_GIM_OPERATION_FAILED;
1359 }
1360
1361 RTMemFree(pvSimPage);
1362 return rc;
1363 }
1364
1365 LogRelFunc(("GIM%u: HyperV: Failed to alloc %u bytes\n", pVCpu->idCpu, cbSimPage));
1366 return VERR_NO_MEMORY;
1367}
1368
1369
1370/**
1371 * Disables the Hyper-V SIM page.
1372 *
1373 * @returns VBox status code.
1374 * @param pVCpu The cross context virtual CPU structure.
1375 */
1376VMMR3_INT_DECL(int) gimR3HvDisableSimPage(PVMCPU pVCpu)
1377{
1378 LogRel(("GIM%u: HyperV: Disabled SIM page\n", pVCpu->idCpu));
1379 /** @todo SIM teardown. */
1380 return VINF_SUCCESS;
1381}
1382
1383
1384
1385/**
1386 * Disables the Hyper-V TSC page.
1387 *
1388 * @returns VBox status code.
1389 * @param pVM The cross context VM structure.
1390 */
1391VMMR3_INT_DECL(int) gimR3HvDisableTscPage(PVM pVM)
1392{
1393 PGIMHV pHv = &pVM->gim.s.u.Hv;
1394 PGIMMMIO2REGION pRegion = &pHv->aMmio2Regions[GIM_HV_REF_TSC_PAGE_REGION_IDX];
1395 if (pRegion->fMapped)
1396 {
1397#if 0
1398 gimR3Mmio2Unmap(pVM, pRegion);
1399 Assert(!pRegion->fMapped);
1400#else
1401 pRegion->fMapped = false;
1402#endif
1403 LogRel(("GIM: HyperV: Disabled TSC page\n"));
1404
1405 TMR3CpuTickParavirtDisable(pVM);
1406 return VINF_SUCCESS;
1407 }
1408 return VERR_GIM_PVTSC_NOT_ENABLED;
1409}
1410
1411
1412/**
1413 * Disables the Hyper-V Hypercall page.
1414 *
1415 * @returns VBox status code.
1416 */
1417VMMR3_INT_DECL(int) gimR3HvDisableHypercallPage(PVM pVM)
1418{
1419 PGIMHV pHv = &pVM->gim.s.u.Hv;
1420 PGIMMMIO2REGION pRegion = &pHv->aMmio2Regions[GIM_HV_HYPERCALL_PAGE_REGION_IDX];
1421 if (pRegion->fMapped)
1422 {
1423#if 0
1424 gimR3Mmio2Unmap(pVM, pRegion);
1425 Assert(!pRegion->fMapped);
1426#else
1427 pRegion->fMapped = false;
1428#endif
1429 LogRel(("GIM: HyperV: Disabled Hypercall-page\n"));
1430 return VINF_SUCCESS;
1431 }
1432 return VERR_GIM_HYPERCALLS_NOT_ENABLED;
1433}
1434
1435
1436/**
1437 * Enables the Hyper-V Hypercall page.
1438 *
1439 * @returns VBox status code.
1440 * @param pVM The cross context VM structure.
1441 * @param GCPhysHypercallPage Where to map the hypercall page.
1442 */
1443VMMR3_INT_DECL(int) gimR3HvEnableHypercallPage(PVM pVM, RTGCPHYS GCPhysHypercallPage)
1444{
1445 PPDMDEVINSR3 pDevIns = pVM->gim.s.pDevInsR3;
1446 PGIMMMIO2REGION pRegion = &pVM->gim.s.u.Hv.aMmio2Regions[GIM_HV_HYPERCALL_PAGE_REGION_IDX];
1447 AssertPtrReturn(pDevIns, VERR_GIM_DEVICE_NOT_REGISTERED);
1448
1449 if (pRegion->fMapped)
1450 {
1451 /*
1452 * Is it already enabled at the given guest-address?
1453 */
1454 if (pRegion->GCPhysPage == GCPhysHypercallPage)
1455 return VINF_SUCCESS;
1456
1457 /*
1458 * If it's mapped at a different address, unmap the previous address.
1459 */
1460 int rc2 = gimR3HvDisableHypercallPage(pVM);
1461 AssertRC(rc2);
1462 }
1463
1464 /*
1465 * Map the hypercall-page at the specified address.
1466 */
1467 Assert(!pRegion->fMapped);
1468
1469 /** @todo this is buggy when large pages are used due to a PGM limitation, see
1470 * @bugref{7532}. Instead of the overlay style mapping, we just
1471 * rewrite guest memory directly. */
1472#if 0
1473 int rc = gimR3Mmio2Map(pVM, pRegion, GCPhysHypercallPage);
1474 if (RT_SUCCESS(rc))
1475 {
1476 Assert(pRegion->GCPhysPage == GCPhysHypercallPage);
1477
1478 /*
1479 * Patch the hypercall-page.
1480 */
1481 size_t cbWritten = 0;
1482 rc = VMMPatchHypercall(pVM, pRegion->pvPageR3, PAGE_SIZE, &cbWritten);
1483 if ( RT_SUCCESS(rc)
1484 && cbWritten < PAGE_SIZE)
1485 {
1486 uint8_t *pbLast = (uint8_t *)pRegion->pvPageR3 + cbWritten;
1487 *pbLast = 0xc3; /* RET */
1488
1489 /*
1490 * Notify VMM that hypercalls are now enabled for all VCPUs.
1491 */
1492 for (VMCPUID i = 0; i < pVM->cCpus; i++)
1493 VMMHypercallsEnable(&pVM->aCpus[i]);
1494
1495 LogRel(("GIM: HyperV: Enabled hypercall page at %#RGp\n", GCPhysHypercallPage));
1496 return VINF_SUCCESS;
1497 }
1498 else
1499 {
1500 if (rc == VINF_SUCCESS)
1501 rc = VERR_GIM_OPERATION_FAILED;
1502 LogRel(("GIM: HyperV: VMMPatchHypercall failed. rc=%Rrc cbWritten=%u\n", rc, cbWritten));
1503 }
1504
1505 gimR3Mmio2Unmap(pVM, pRegion);
1506 }
1507
1508 LogRel(("GIM: HyperV: gimR3Mmio2Map failed. rc=%Rrc\n", rc));
1509 return rc;
1510#else
1511 AssertReturn(pRegion->cbRegion == PAGE_SIZE, VERR_GIM_IPE_3);
1512 void *pvHypercallPage = RTMemAllocZ(PAGE_SIZE);
1513 if (RT_UNLIKELY(!pvHypercallPage))
1514 {
1515 LogRelFunc(("Failed to alloc %u bytes\n", PAGE_SIZE));
1516 return VERR_NO_MEMORY;
1517 }
1518
1519 /*
1520 * Patch the hypercall-page.
1521 */
1522 size_t cbWritten = 0;
1523 int rc = VMMPatchHypercall(pVM, pvHypercallPage, PAGE_SIZE, &cbWritten);
1524 if ( RT_SUCCESS(rc)
1525 && cbWritten < PAGE_SIZE)
1526 {
1527 uint8_t *pbLast = (uint8_t *)pvHypercallPage + cbWritten;
1528 *pbLast = 0xc3; /* RET */
1529
1530 rc = PGMPhysSimpleWriteGCPhys(pVM, GCPhysHypercallPage, pvHypercallPage, PAGE_SIZE);
1531 if (RT_SUCCESS(rc))
1532 {
1533 pRegion->GCPhysPage = GCPhysHypercallPage;
1534 pRegion->fMapped = true;
1535 LogRel(("GIM: HyperV: Enabled hypercall page at %#RGp\n", GCPhysHypercallPage));
1536 }
1537 else
1538 LogRel(("GIM: HyperV: PGMPhysSimpleWriteGCPhys failed during hypercall page setup. rc=%Rrc\n", rc));
1539 }
1540 else
1541 {
1542 if (rc == VINF_SUCCESS)
1543 rc = VERR_GIM_OPERATION_FAILED;
1544 LogRel(("GIM: HyperV: VMMPatchHypercall failed. rc=%Rrc cbWritten=%u\n", rc, cbWritten));
1545 }
1546
1547 RTMemFree(pvHypercallPage);
1548 return rc;
1549#endif
1550}
1551
1552
1553/**
1554 * Initializes Hyper-V guest hypercall support.
1555 *
1556 * @returns VBox status code.
1557 * @param pVM The cross context VM structure.
1558 */
1559static int gimR3HvInitHypercallSupport(PVM pVM)
1560{
1561 PGIMHV pHv = &pVM->gim.s.u.Hv;
1562 pHv->pbHypercallIn = (uint8_t *)RTMemAllocZ(GIM_HV_PAGE_SIZE);
1563 if (RT_LIKELY(pHv->pbHypercallIn))
1564 {
1565 pHv->pbHypercallOut = (uint8_t *)RTMemAllocZ(GIM_HV_PAGE_SIZE);
1566 if (RT_LIKELY(pHv->pbHypercallOut))
1567 return VINF_SUCCESS;
1568 RTMemFree(pHv->pbHypercallIn);
1569 }
1570 return VERR_NO_MEMORY;
1571}
1572
1573
1574/**
1575 * Terminates Hyper-V guest hypercall support.
1576 *
1577 * @param pVM The cross context VM structure.
1578 */
1579static void gimR3HvTermHypercallSupport(PVM pVM)
1580{
1581 PGIMHV pHv = &pVM->gim.s.u.Hv;
1582 RTMemFree(pHv->pbHypercallIn);
1583 pHv->pbHypercallIn = NULL;
1584
1585 RTMemFree(pHv->pbHypercallOut);
1586 pHv->pbHypercallOut = NULL;
1587}
1588
1589
1590/**
1591 * Initializes Hyper-V guest debug support.
1592 *
1593 * @returns VBox status code.
1594 * @param pVM The cross context VM structure.
1595 */
1596static int gimR3HvInitDebugSupport(PVM pVM)
1597{
1598 PGIMHV pHv = &pVM->gim.s.u.Hv;
1599 if ( (pHv->uPartFlags & GIM_HV_PART_FLAGS_DEBUGGING)
1600 || pHv->fIsInterfaceVs)
1601 {
1602 pHv->fDbgEnabled = true;
1603 pHv->pvDbgBuffer = RTMemAllocZ(PAGE_SIZE);
1604 if (!pHv->pvDbgBuffer)
1605 return VERR_NO_MEMORY;
1606 }
1607 return VINF_SUCCESS;
1608}
1609
1610
1611/**
1612 * Terminates Hyper-V guest debug support.
1613 *
1614 * @param pVM The cross context VM structure.
1615 */
1616static void gimR3HvTermDebugSupport(PVM pVM)
1617{
1618 PGIMHV pHv = &pVM->gim.s.u.Hv;
1619 if (pHv->pvDbgBuffer)
1620 {
1621 RTMemFree(pHv->pvDbgBuffer);
1622 pHv->pvDbgBuffer = NULL;
1623 }
1624}
1625
1626
1627/**
1628 * Reads data from a debugger connection, asynchronous.
1629 *
1630 * @returns VBox status code.
1631 * @param pVM The cross context VM structure.
1632 * @param pvBuf Where to read the data.
1633 * @param cbBuf Size of the read buffer @a pvBuf, must be >= @a cbRead.
1634 * @param cbRead Number of bytes to read.
1635 * @param pcbRead Where to store how many bytes were really read.
1636 * @param cMsTimeout Timeout of the read operation in milliseconds.
1637 * @param fUdpPkt Whether the debug data returned in @a pvBuf needs to be
1638 * encapsulated in a UDP frame.
1639 *
1640 * @thread EMT.
1641 */
1642VMMR3_INT_DECL(int) gimR3HvDebugRead(PVM pVM, void *pvBuf, uint32_t cbBuf, uint32_t cbRead, uint32_t *pcbRead,
1643 uint32_t cMsTimeout, bool fUdpPkt)
1644{
1645 NOREF(cMsTimeout); /** @todo implement timeout. */
1646 AssertCompile(sizeof(size_t) >= sizeof(uint32_t));
1647 AssertReturn(cbBuf >= cbRead, VERR_INVALID_PARAMETER);
1648
1649 int rc;
1650 if (!fUdpPkt)
1651 {
1652 /*
1653 * Read the raw debug data.
1654 */
1655 size_t cbReallyRead = cbRead;
1656 rc = gimR3DebugRead(pVM, pvBuf, &cbReallyRead, gimR3HvDebugBufReadCompleted);
1657 *pcbRead = (uint32_t)cbReallyRead;
1658 }
1659 else
1660 {
1661 /*
1662 * Guest requires UDP encapsulated frames.
1663 */
1664 PGIMHV pHv = &pVM->gim.s.u.Hv;
1665 rc = VERR_GIM_IPE_1;
1666 switch (pHv->enmDbgReply)
1667 {
1668 case GIMHVDEBUGREPLY_UDP:
1669 {
1670 size_t cbReallyRead = cbRead;
1671 rc = gimR3DebugRead(pVM, pvBuf, &cbReallyRead, gimR3HvDebugBufReadCompleted);
1672 if ( RT_SUCCESS(rc)
1673 && cbReallyRead > 0)
1674 {
1675 uint8_t abFrame[sizeof(RTNETETHERHDR) + RTNETIPV4_MIN_LEN + sizeof(RTNETUDP)];
1676 if (cbReallyRead + sizeof(abFrame) <= cbBuf)
1677 {
1678 /*
1679 * Windows guests pumps ethernet frames over the Hyper-V debug connection as
1680 * explained in gimR3HvHypercallPostDebugData(). Here, we reconstruct the packet
1681 * with the guest's self-chosen IP ARP address we saved in pHv->DbgGuestAddr.
1682 *
1683 * Note! We really need to pass the minimum IPv4 header length. The Windows 10 guest
1684 * is -not- happy if we include the IPv4 options field, i.e. using sizeof(RTNETIPV4)
1685 * instead of RTNETIPV4_MIN_LEN.
1686 */
1687 RT_ZERO(abFrame);
1688 PRTNETETHERHDR pEthHdr = (PRTNETETHERHDR)&abFrame[0];
1689 PRTNETIPV4 pIpHdr = (PRTNETIPV4) (pEthHdr + 1);
1690 PRTNETUDP pUdpHdr = (PRTNETUDP) ((uint8_t *)pIpHdr + RTNETIPV4_MIN_LEN);
1691
1692 /* Ethernet */
1693 pEthHdr->EtherType = RT_H2N_U16_C(RTNET_ETHERTYPE_IPV4);
1694 /* IPv4 */
1695 pIpHdr->ip_v = 4;
1696 pIpHdr->ip_hl = RTNETIPV4_MIN_LEN / sizeof(uint32_t);
1697 pIpHdr->ip_tos = 0;
1698 pIpHdr->ip_len = RT_H2N_U16((uint16_t)cbReallyRead + sizeof(RTNETUDP) + RTNETIPV4_MIN_LEN);
1699 pIpHdr->ip_id = 0;
1700 pIpHdr->ip_off = 0;
1701 pIpHdr->ip_ttl = 255;
1702 pIpHdr->ip_p = RTNETIPV4_PROT_UDP;
1703 pIpHdr->ip_sum = 0;
1704 pIpHdr->ip_src.u = 0;
1705 pIpHdr->ip_dst.u = pHv->DbgGuestIp4Addr.u;
1706 pIpHdr->ip_sum = RTNetIPv4HdrChecksum(pIpHdr);
1707 /* UDP */
1708 pUdpHdr->uh_dport = pHv->uUdpGuestSrcPort;
1709 pUdpHdr->uh_sport = pHv->uUdpGuestDstPort;
1710 pUdpHdr->uh_ulen = RT_H2N_U16_C((uint16_t)cbReallyRead + sizeof(*pUdpHdr));
1711
1712 /* Make room by moving the payload and prepending the headers. */
1713 uint8_t *pbData = (uint8_t *)pvBuf;
1714 memmove(pbData + sizeof(abFrame), pbData, cbReallyRead);
1715 memcpy(pbData, &abFrame[0], sizeof(abFrame));
1716
1717 /* Update the adjusted sizes. */
1718 cbReallyRead += sizeof(abFrame);
1719 }
1720 else
1721 rc = VERR_BUFFER_UNDERFLOW;
1722 }
1723 *pcbRead = (uint32_t)cbReallyRead;
1724 break;
1725 }
1726
1727 case GIMHVDEBUGREPLY_ARP_REPLY:
1728 {
1729 uint32_t const cbArpReplyPkt = sizeof(g_abArpReply);
1730 if (cbBuf >= cbArpReplyPkt)
1731 {
1732 memcpy(pvBuf, g_abArpReply, cbArpReplyPkt);
1733 rc = VINF_SUCCESS;
1734 *pcbRead = cbArpReplyPkt;
1735 pHv->enmDbgReply = GIMHVDEBUGREPLY_ARP_REPLY_SENT;
1736 }
1737 else
1738 {
1739 rc = VERR_BUFFER_UNDERFLOW;
1740 *pcbRead = 0;
1741 }
1742 break;
1743 }
1744
1745 case GIMHVDEBUGREPLY_DHCP_OFFER:
1746 {
1747 uint32_t const cbDhcpOfferPkt = sizeof(g_abDhcpOffer);
1748 if (cbBuf >= cbDhcpOfferPkt)
1749 {
1750 memcpy(pvBuf, g_abDhcpOffer, cbDhcpOfferPkt);
1751 PRTNETETHERHDR pEthHdr = (PRTNETETHERHDR)pvBuf;
1752 PRTNETIPV4 pIpHdr = (PRTNETIPV4) (pEthHdr + 1);
1753 PRTNETUDP pUdpHdr = (PRTNETUDP) ((uint8_t *)pIpHdr + RTNETIPV4_MIN_LEN);
1754 PRTNETBOOTP pBootpHdr = (PRTNETBOOTP) (pUdpHdr + 1);
1755 pBootpHdr->bp_xid = pHv->uDbgBootpXId;
1756
1757 rc = VINF_SUCCESS;
1758 *pcbRead = cbDhcpOfferPkt;
1759 pHv->enmDbgReply = GIMHVDEBUGREPLY_DHCP_OFFER_SENT;
1760 LogRel(("GIM: HyperV: Debug DHCP offered IP address %RTnaipv4, transaction Id %#x\n", pBootpHdr->bp_yiaddr,
1761 RT_N2H_U32(pHv->uDbgBootpXId)));
1762 }
1763 else
1764 {
1765 rc = VERR_BUFFER_UNDERFLOW;
1766 *pcbRead = 0;
1767 }
1768 break;
1769 }
1770
1771 case GIMHVDEBUGREPLY_DHCP_ACK:
1772 {
1773 uint32_t const cbDhcpAckPkt = sizeof(g_abDhcpAck);
1774 if (cbBuf >= cbDhcpAckPkt)
1775 {
1776 memcpy(pvBuf, g_abDhcpAck, cbDhcpAckPkt);
1777 PRTNETETHERHDR pEthHdr = (PRTNETETHERHDR)pvBuf;
1778 PRTNETIPV4 pIpHdr = (PRTNETIPV4) (pEthHdr + 1);
1779 PRTNETUDP pUdpHdr = (PRTNETUDP) ((uint8_t *)pIpHdr + RTNETIPV4_MIN_LEN);
1780 PRTNETBOOTP pBootpHdr = (PRTNETBOOTP) (pUdpHdr + 1);
1781 pBootpHdr->bp_xid = pHv->uDbgBootpXId;
1782
1783 rc = VINF_SUCCESS;
1784 *pcbRead = cbDhcpAckPkt;
1785 pHv->enmDbgReply = GIMHVDEBUGREPLY_DHCP_ACK_SENT;
1786 LogRel(("GIM: HyperV: Debug DHCP acknowledged IP address %RTnaipv4, transaction Id %#x\n",
1787 pBootpHdr->bp_yiaddr, RT_N2H_U32(pHv->uDbgBootpXId)));
1788 }
1789 else
1790 {
1791 rc = VERR_BUFFER_UNDERFLOW;
1792 *pcbRead = 0;
1793 }
1794 break;
1795 }
1796
1797 case GIMHVDEBUGREPLY_ARP_REPLY_SENT:
1798 case GIMHVDEBUGREPLY_DHCP_OFFER_SENT:
1799 case GIMHVDEBUGREPLY_DHCP_ACK_SENT:
1800 {
1801 rc = VINF_SUCCESS;
1802 *pcbRead = 0;
1803 break;
1804 }
1805
1806 default:
1807 {
1808 AssertMsgFailed(("GIM: HyperV: Invalid/unimplemented debug reply type %u\n", pHv->enmDbgReply));
1809 rc = VERR_INTERNAL_ERROR_2;
1810 }
1811 }
1812 Assert(rc != VERR_GIM_IPE_1);
1813
1814#ifdef DEBUG_ramshankar
1815 if ( rc == VINF_SUCCESS
1816 && *pcbRead > 0)
1817 {
1818 RTSOCKET hSocket;
1819 int rc2 = RTUdpCreateClientSocket("localhost", 52000, NULL, &hSocket);
1820 if (RT_SUCCESS(rc2))
1821 {
1822 size_t cbTmpWrite = *pcbRead;
1823 RTSocketWriteNB(hSocket, pvBuf, *pcbRead, &cbTmpWrite); NOREF(cbTmpWrite);
1824 RTSocketClose(hSocket);
1825 }
1826 }
1827#endif
1828 }
1829
1830 return rc;
1831}
1832
1833
1834/**
1835 * Writes data to the debugger connection, asynchronous.
1836 *
1837 * @returns VBox status code.
1838 * @param pVM The cross context VM structure.
1839 * @param pvData Pointer to the data to be written.
1840 * @param cbWrite Size of the write buffer @a pvData.
1841 * @param pcbWritten Where to store the number of bytes written.
1842 * @param fUdpPkt Whether the debug data in @a pvData is encapsulated in a
1843 * UDP frame.
1844 *
1845 * @thread EMT.
1846 */
1847VMMR3_INT_DECL(int) gimR3HvDebugWrite(PVM pVM, void *pvData, uint32_t cbWrite, uint32_t *pcbWritten, bool fUdpPkt)
1848{
1849 Assert(cbWrite > 0);
1850
1851 PGIMHV pHv = &pVM->gim.s.u.Hv;
1852 bool fIgnorePkt = false;
1853 uint8_t *pbData = (uint8_t *)pvData;
1854 if (fUdpPkt)
1855 {
1856#ifdef DEBUG_ramshankar
1857 RTSOCKET hSocket;
1858 int rc2 = RTUdpCreateClientSocket("localhost", 52000, NULL, &hSocket);
1859 if (RT_SUCCESS(rc2))
1860 {
1861 size_t cbTmpWrite = cbWrite;
1862 RTSocketWriteNB(hSocket, pbData, cbWrite, &cbTmpWrite); NOREF(cbTmpWrite);
1863 RTSocketClose(hSocket);
1864 }
1865#endif
1866 /*
1867 * Windows guests sends us ethernet frames over the Hyper-V debug connection.
1868 * It sends DHCP/ARP queries with zero'd out MAC addresses and requires fudging up the
1869 * packets somewhere.
1870 *
1871 * The Microsoft WinDbg debugger talks UDP and thus only expects the actual debug
1872 * protocol payload.
1873 *
1874 * If the guest is configured with the "nodhcp" option it sends ARP queries with
1875 * a self-chosen IP and after a couple of attempts of receiving no replies, the guest
1876 * picks its own IP address. After this, the guest starts sending the UDP packets
1877 * we require. We thus ignore the initial ARP packets until the guest eventually
1878 * starts talking UDP. Then we can finally feed the UDP payload over the debug
1879 * connection.
1880 *
1881 * When 'kdvm.dll' is the debug transport in the guest (Windows 7), it doesn't bother
1882 * with this DHCP/ARP phase. It starts sending debug data in a UDP frame right away.
1883 */
1884 if (cbWrite > sizeof(RTNETETHERHDR))
1885 {
1886 PCRTNETETHERHDR pEtherHdr = (PCRTNETETHERHDR)pbData;
1887 if (pEtherHdr->EtherType == RT_H2N_U16_C(RTNET_ETHERTYPE_IPV4))
1888 {
1889 if (cbWrite > sizeof(RTNETETHERHDR) + RTNETIPV4_MIN_LEN + RTNETUDP_MIN_LEN)
1890 {
1891 size_t const cbMaxIpHdr = cbWrite - sizeof(RTNETETHERHDR) - sizeof(RTNETUDP) - 1;
1892 size_t const cbMaxIpPkt = cbWrite - sizeof(RTNETETHERHDR);
1893 PCRTNETIPV4 pIp4Hdr = (PCRTNETIPV4)(pbData + sizeof(RTNETETHERHDR));
1894 bool const fValidIp4 = RTNetIPv4IsHdrValid(pIp4Hdr, cbMaxIpHdr, cbMaxIpPkt, false /*fChecksum*/);
1895 if ( fValidIp4
1896 && pIp4Hdr->ip_p == RTNETIPV4_PROT_UDP)
1897 {
1898 uint32_t const cbIpHdr = pIp4Hdr->ip_hl * 4;
1899 uint32_t const cbMaxUdpPkt = cbWrite - sizeof(RTNETETHERHDR) - cbIpHdr;
1900 PCRTNETUDP pUdpHdr = (PCRTNETUDP)((uint8_t *)pIp4Hdr + cbIpHdr);
1901 if ( pUdpHdr->uh_ulen > RT_H2N_U16(sizeof(RTNETUDP))
1902 && pUdpHdr->uh_ulen <= RT_H2N_U16((uint16_t)cbMaxUdpPkt))
1903 {
1904 /*
1905 * Check for DHCP.
1906 */
1907 bool fBuggyPkt = false;
1908 size_t const cbUdpPkt = cbMaxIpPkt - cbIpHdr;
1909 if ( pUdpHdr->uh_dport == RT_N2H_U16_C(RTNETIPV4_PORT_BOOTPS)
1910 && pUdpHdr->uh_sport == RT_N2H_U16_C(RTNETIPV4_PORT_BOOTPC))
1911 {
1912 PCRTNETBOOTP pDhcpPkt = (PCRTNETBOOTP)(pUdpHdr + 1);
1913 uint8_t bMsgType;
1914 if ( cbMaxIpPkt >= cbIpHdr + RTNETUDP_MIN_LEN + RTNETBOOTP_DHCP_MIN_LEN
1915 && RTNetIPv4IsDHCPValid(pUdpHdr, pDhcpPkt, cbUdpPkt - sizeof(*pUdpHdr), &bMsgType))
1916 {
1917 switch (bMsgType)
1918 {
1919 case RTNET_DHCP_MT_DISCOVER:
1920 pHv->enmDbgReply = GIMHVDEBUGREPLY_DHCP_OFFER;
1921 pHv->uDbgBootpXId = pDhcpPkt->bp_xid;
1922 break;
1923 case RTNET_DHCP_MT_REQUEST:
1924 pHv->enmDbgReply = GIMHVDEBUGREPLY_DHCP_ACK;
1925 pHv->uDbgBootpXId = pDhcpPkt->bp_xid;
1926 break;
1927 default:
1928 LogRelMax(5, ("GIM: HyperV: Debug DHCP MsgType %#x not implemented! Packet dropped\n",
1929 bMsgType));
1930 break;
1931 }
1932 fIgnorePkt = true;
1933 }
1934 else if ( pIp4Hdr->ip_src.u == GIMHV_DEBUGCLIENT_IPV4
1935 && pIp4Hdr->ip_dst.u == 0)
1936 {
1937 /*
1938 * Windows 8.1 seems to be sending malformed BOOTP packets at the final stage of the
1939 * debugger sequence. It appears that a previously sent DHCP request buffer wasn't cleared
1940 * in the guest and they re-use it instead of sending a zero destination+source port packet
1941 * as expected below.
1942 *
1943 * We workaround Microsoft's bug here, or at least, I'm classifying it as a bug to
1944 * preserve my own sanity, see @bugref{8006#c54}.
1945 */
1946 fBuggyPkt = true;
1947 }
1948 }
1949
1950 if ( ( !pUdpHdr->uh_dport
1951 && !pUdpHdr->uh_sport)
1952 || fBuggyPkt)
1953 {
1954 /*
1955 * Extract the UDP payload and pass it to the debugger and record the guest IP address.
1956 *
1957 * Hyper-V sends UDP debugger packets with source and destination port as 0 except in the
1958 * aforementioned buggy case. The buggy packet case requires us to remember the ports and
1959 * reply to them, otherwise the guest won't receive the replies we sent with port 0.
1960 */
1961 uint32_t const cbFrameHdr = sizeof(RTNETETHERHDR) + cbIpHdr + sizeof(RTNETUDP);
1962 pbData += cbFrameHdr;
1963 cbWrite -= cbFrameHdr;
1964 pHv->DbgGuestIp4Addr.u = pIp4Hdr->ip_src.u;
1965 pHv->uUdpGuestDstPort = pUdpHdr->uh_dport;
1966 pHv->uUdpGuestSrcPort = pUdpHdr->uh_sport;
1967 pHv->enmDbgReply = GIMHVDEBUGREPLY_UDP;
1968 }
1969 else
1970 {
1971 LogFlow(("GIM: HyperV: Ignoring UDP packet SourcePort=%u DstPort=%u\n", pUdpHdr->uh_sport,
1972 pUdpHdr->uh_dport));
1973 fIgnorePkt = true;
1974 }
1975 }
1976 else
1977 {
1978 LogFlow(("GIM: HyperV: Ignoring malformed UDP packet. cbMaxUdpPkt=%u UdpPkt.len=%u\n", cbMaxUdpPkt,
1979 RT_N2H_U16(pUdpHdr->uh_ulen)));
1980 fIgnorePkt = true;
1981 }
1982 }
1983 else
1984 {
1985 LogFlow(("GIM: HyperV: Ignoring non-IP / non-UDP packet. fValidIp4=%RTbool Proto=%u\n", fValidIp4,
1986 pIp4Hdr->ip_p));
1987 fIgnorePkt = true;
1988 }
1989 }
1990 else
1991 {
1992 LogFlow(("GIM: HyperV: Ignoring IPv4 packet; too short to be valid UDP. cbWrite=%u\n", cbWrite));
1993 fIgnorePkt = true;
1994 }
1995 }
1996 else if (pEtherHdr->EtherType == RT_H2N_U16_C(RTNET_ETHERTYPE_ARP))
1997 {
1998 /*
1999 * Check for targetted ARP query.
2000 */
2001 PCRTNETARPHDR pArpHdr = (PCRTNETARPHDR)(pbData + sizeof(RTNETETHERHDR));
2002 if ( pArpHdr->ar_hlen == sizeof(RTMAC)
2003 && pArpHdr->ar_plen == sizeof(RTNETADDRIPV4)
2004 && pArpHdr->ar_htype == RT_H2N_U16(RTNET_ARP_ETHER)
2005 && pArpHdr->ar_ptype == RT_H2N_U16(RTNET_ETHERTYPE_IPV4))
2006 {
2007 uint16_t uArpOp = pArpHdr->ar_oper;
2008 if (uArpOp == RT_H2N_U16_C(RTNET_ARPOP_REQUEST))
2009 {
2010 PCRTNETARPIPV4 pArpPkt = (PCRTNETARPIPV4)pArpHdr;
2011 bool fGratuitous = pArpPkt->ar_spa.u == pArpPkt->ar_tpa.u;
2012 if ( !fGratuitous
2013 && pArpPkt->ar_spa.u == GIMHV_DEBUGCLIENT_IPV4
2014 && pArpPkt->ar_tpa.u == GIMHV_DEBUGSERVER_IPV4)
2015 {
2016 pHv->enmDbgReply = GIMHVDEBUGREPLY_ARP_REPLY;
2017 }
2018 }
2019 }
2020 fIgnorePkt = true;
2021 }
2022 else
2023 {
2024 LogFlow(("GIM: HyperV: Ignoring non-IP packet. Ethertype=%#x\n", RT_N2H_U16(pEtherHdr->EtherType)));
2025 fIgnorePkt = true;
2026 }
2027 }
2028 }
2029
2030 if (!fIgnorePkt)
2031 {
2032 AssertCompile(sizeof(size_t) >= sizeof(uint32_t));
2033 size_t cbWriteBuf = cbWrite;
2034 int rc = gimR3DebugWrite(pVM, pbData, &cbWriteBuf);
2035 if ( RT_SUCCESS(rc)
2036 && cbWriteBuf == cbWrite)
2037 *pcbWritten = (uint32_t)cbWriteBuf;
2038 else
2039 *pcbWritten = 0;
2040 }
2041 else
2042 *pcbWritten = cbWrite;
2043
2044 return VINF_SUCCESS;
2045}
2046
2047
2048/**
2049 * Performs the HvPostDebugData hypercall.
2050 *
2051 * @returns VBox status code.
2052 * @param pVM The cross context VM structure.
2053 * @param prcHv Where to store the result of the hypercall operation.
2054 *
2055 * @thread EMT.
2056 */
2057VMMR3_INT_DECL(int) gimR3HvHypercallPostDebugData(PVM pVM, int *prcHv)
2058{
2059 AssertPtr(pVM);
2060 AssertPtr(prcHv);
2061 PGIMHV pHv = &pVM->gim.s.u.Hv;
2062 int rcHv = GIM_HV_STATUS_OPERATION_DENIED;
2063
2064 /*
2065 * Grab the parameters.
2066 */
2067 PGIMHVDEBUGPOSTIN pIn = (PGIMHVDEBUGPOSTIN)pHv->pbHypercallIn;
2068 AssertPtrReturn(pIn, VERR_GIM_IPE_1);
2069 uint32_t cbWrite = pIn->cbWrite;
2070 uint32_t fFlags = pIn->fFlags;
2071 uint8_t *pbData = ((uint8_t *)pIn) + sizeof(PGIMHVDEBUGPOSTIN);
2072
2073 PGIMHVDEBUGPOSTOUT pOut = (PGIMHVDEBUGPOSTOUT)pHv->pbHypercallOut;
2074
2075 /*
2076 * Perform the hypercall.
2077 */
2078#if 0
2079 /* Currently disabled as Windows 10 guest passes us undocumented flags. */
2080 if (fFlags & ~GIM_HV_DEBUG_POST_OPTIONS_MASK))
2081 rcHv = GIM_HV_STATUS_INVALID_PARAMETER;
2082#else
2083 RT_NOREF1(fFlags);
2084#endif
2085 if (cbWrite > GIM_HV_DEBUG_MAX_DATA_SIZE)
2086 rcHv = GIM_HV_STATUS_INVALID_PARAMETER;
2087 else if (!cbWrite)
2088 {
2089 rcHv = GIM_HV_STATUS_SUCCESS;
2090 pOut->cbPending = 0;
2091 }
2092 else if (cbWrite > 0)
2093 {
2094 uint32_t cbWritten = 0;
2095 int rc2 = gimR3HvDebugWrite(pVM, pbData, cbWrite, &cbWritten, pHv->fIsVendorMsHv /*fUdpPkt*/);
2096 if ( RT_SUCCESS(rc2)
2097 && cbWritten == cbWrite)
2098 {
2099 pOut->cbPending = 0;
2100 rcHv = GIM_HV_STATUS_SUCCESS;
2101 }
2102 else
2103 rcHv = GIM_HV_STATUS_INSUFFICIENT_BUFFER;
2104 }
2105
2106 /*
2107 * Update the guest memory with result.
2108 */
2109 int rc = PGMPhysSimpleWriteGCPhys(pVM, pHv->GCPhysHypercallOut, pHv->pbHypercallOut, sizeof(GIMHVDEBUGPOSTOUT));
2110 if (RT_FAILURE(rc))
2111 {
2112 LogRelMax(10, ("GIM: HyperV: HvPostDebugData failed to update guest memory. rc=%Rrc\n", rc));
2113 rc = VERR_GIM_HYPERCALL_MEMORY_WRITE_FAILED;
2114 }
2115 else
2116 Assert(rc == VINF_SUCCESS);
2117
2118 *prcHv = rcHv;
2119 return rc;
2120}
2121
2122
2123/**
2124 * Performs the HvRetrieveDebugData hypercall.
2125 *
2126 * @returns VBox status code.
2127 * @param pVM The cross context VM structure.
2128 * @param prcHv Where to store the result of the hypercall operation.
2129 *
2130 * @thread EMT.
2131 */
2132VMMR3_INT_DECL(int) gimR3HvHypercallRetrieveDebugData(PVM pVM, int *prcHv)
2133{
2134 AssertPtr(pVM);
2135 AssertPtr(prcHv);
2136 PGIMHV pHv = &pVM->gim.s.u.Hv;
2137 int rcHv = GIM_HV_STATUS_OPERATION_DENIED;
2138
2139 /*
2140 * Grab the parameters.
2141 */
2142 PGIMHVDEBUGRETRIEVEIN pIn = (PGIMHVDEBUGRETRIEVEIN)pHv->pbHypercallIn;
2143 AssertPtrReturn(pIn, VERR_GIM_IPE_1);
2144 uint32_t cbRead = pIn->cbRead;
2145 uint32_t fFlags = pIn->fFlags;
2146 uint64_t uTimeout = pIn->u64Timeout;
2147 uint32_t cMsTimeout = (fFlags & GIM_HV_DEBUG_RETREIVE_LOOP) ? (uTimeout * 100) / RT_NS_1MS_64 : 0;
2148
2149 PGIMHVDEBUGRETRIEVEOUT pOut = (PGIMHVDEBUGRETRIEVEOUT)pHv->pbHypercallOut;
2150 AssertPtrReturn(pOut, VERR_GIM_IPE_2);
2151 uint32_t *pcbReallyRead = &pOut->cbRead;
2152 uint32_t *pcbRemainingRead = &pOut->cbRemaining;
2153 void *pvData = ((uint8_t *)pOut) + sizeof(GIMHVDEBUGRETRIEVEOUT);
2154
2155 /*
2156 * Perform the hypercall.
2157 */
2158 *pcbReallyRead = 0;
2159 *pcbRemainingRead = cbRead;
2160#if 0
2161 /* Currently disabled as Windows 10 guest passes us undocumented flags. */
2162 if (fFlags & ~GIM_HV_DEBUG_RETREIVE_OPTIONS_MASK)
2163 rcHv = GIM_HV_STATUS_INVALID_PARAMETER;
2164#endif
2165 if (cbRead > GIM_HV_DEBUG_MAX_DATA_SIZE)
2166 rcHv = GIM_HV_STATUS_INVALID_PARAMETER;
2167 else if (fFlags & GIM_HV_DEBUG_RETREIVE_TEST_ACTIVITY)
2168 rcHv = GIM_HV_STATUS_SUCCESS; /** @todo implement this. */
2169 else if (!cbRead)
2170 rcHv = GIM_HV_STATUS_SUCCESS;
2171 else if (cbRead > 0)
2172 {
2173 int rc2 = gimR3HvDebugRead(pVM, pvData, GIM_HV_PAGE_SIZE, cbRead, pcbReallyRead, cMsTimeout,
2174 pHv->fIsVendorMsHv /*fUdpPkt*/);
2175 Assert(*pcbReallyRead <= cbRead);
2176 if ( RT_SUCCESS(rc2)
2177 && *pcbReallyRead > 0)
2178 {
2179 *pcbRemainingRead = cbRead - *pcbReallyRead;
2180 rcHv = GIM_HV_STATUS_SUCCESS;
2181 }
2182 else
2183 rcHv = GIM_HV_STATUS_NO_DATA;
2184 }
2185
2186 /*
2187 * Update the guest memory with result.
2188 */
2189 int rc = PGMPhysSimpleWriteGCPhys(pVM, pHv->GCPhysHypercallOut, pHv->pbHypercallOut,
2190 sizeof(GIMHVDEBUGRETRIEVEOUT) + *pcbReallyRead);
2191 if (RT_FAILURE(rc))
2192 {
2193 LogRelMax(10, ("GIM: HyperV: HvRetrieveDebugData failed to update guest memory. rc=%Rrc\n", rc));
2194 rc = VERR_GIM_HYPERCALL_MEMORY_WRITE_FAILED;
2195 }
2196 else
2197 Assert(rc == VINF_SUCCESS);
2198
2199 *prcHv = rcHv;
2200 return rc;
2201}
2202
2203
2204/**
2205 * Performs the HvExtCallQueryCapabilities extended hypercall.
2206 *
2207 * @returns VBox status code.
2208 * @param pVM The cross context VM structure.
2209 * @param prcHv Where to store the result of the hypercall operation.
2210 *
2211 * @thread EMT.
2212 */
2213VMMR3_INT_DECL(int) gimR3HvHypercallExtQueryCap(PVM pVM, int *prcHv)
2214{
2215 AssertPtr(pVM);
2216 AssertPtr(prcHv);
2217 PGIMHV pHv = &pVM->gim.s.u.Hv;
2218
2219 /*
2220 * Grab the parameters.
2221 */
2222 PGIMHVEXTQUERYCAP pOut = (PGIMHVEXTQUERYCAP)pHv->pbHypercallOut;
2223
2224 /*
2225 * Perform the hypercall.
2226 */
2227 pOut->fCapabilities = GIM_HV_EXT_HYPERCALL_CAP_ZERO_MEM;
2228
2229 /*
2230 * Update the guest memory with result.
2231 */
2232 int rcHv;
2233 int rc = PGMPhysSimpleWriteGCPhys(pVM, pHv->GCPhysHypercallOut, pHv->pbHypercallOut, sizeof(GIMHVEXTQUERYCAP));
2234 if (RT_SUCCESS(rc))
2235 {
2236 rcHv = GIM_HV_STATUS_SUCCESS;
2237 LogRel(("GIM: HyperV: Queried extended hypercall capabilities %#RX64 at %#RGp\n", pOut->fCapabilities,
2238 pHv->GCPhysHypercallOut));
2239 }
2240 else
2241 {
2242 rcHv = GIM_HV_STATUS_OPERATION_DENIED;
2243 LogRelMax(10, ("GIM: HyperV: HvHypercallExtQueryCap failed to update guest memory. rc=%Rrc\n", rc));
2244 rc = VERR_GIM_HYPERCALL_MEMORY_WRITE_FAILED;
2245 }
2246
2247 *prcHv = rcHv;
2248 return rc;
2249}
2250
2251
2252/**
2253 * Performs the HvExtCallGetBootZeroedMemory extended hypercall.
2254 *
2255 * @returns VBox status code.
2256 * @param pVM The cross context VM structure.
2257 * @param prcHv Where to store the result of the hypercall operation.
2258 *
2259 * @thread EMT.
2260 */
2261VMMR3_INT_DECL(int) gimR3HvHypercallExtGetBootZeroedMem(PVM pVM, int *prcHv)
2262{
2263 AssertPtr(pVM);
2264 AssertPtr(prcHv);
2265 PGIMHV pHv = &pVM->gim.s.u.Hv;
2266
2267 /*
2268 * Grab the parameters.
2269 */
2270 PGIMHVEXTGETBOOTZEROMEM pOut = (PGIMHVEXTGETBOOTZEROMEM)pHv->pbHypercallOut;
2271
2272 /*
2273 * Perform the hypercall.
2274 */
2275 uint32_t const cRanges = PGMR3PhysGetRamRangeCount(pVM);
2276 pOut->cPages = 0;
2277 for (uint32_t iRange = 0; iRange < cRanges; iRange++)
2278 {
2279 RTGCPHYS GCPhysStart;
2280 RTGCPHYS GCPhysEnd;
2281 int rc = PGMR3PhysGetRange(pVM, iRange, &GCPhysStart, &GCPhysEnd, NULL /* pszDesc */, NULL /* fIsMmio */);
2282 if (RT_FAILURE(rc))
2283 {
2284 LogRelMax(10, ("GIM: HyperV: HvHypercallExtGetBootZeroedMem: PGMR3PhysGetRange failed for iRange(%u) rc=%Rrc\n",
2285 iRange, rc));
2286 *prcHv = GIM_HV_STATUS_OPERATION_DENIED;
2287 return rc;
2288 }
2289
2290 RTGCPHYS const cbRange = RT_ALIGN(GCPhysEnd - GCPhysStart + 1, PAGE_SIZE);
2291 pOut->cPages += cbRange >> GIM_HV_PAGE_SHIFT;
2292 if (iRange == 0)
2293 pOut->GCPhysStart = GCPhysStart;
2294 }
2295
2296 /*
2297 * Update the guest memory with result.
2298 */
2299 int rcHv;
2300 int rc = PGMPhysSimpleWriteGCPhys(pVM, pHv->GCPhysHypercallOut, pHv->pbHypercallOut, sizeof(GIMHVEXTGETBOOTZEROMEM));
2301 if (RT_SUCCESS(rc))
2302 {
2303 LogRel(("GIM: HyperV: Queried boot zeroed guest memory range (starting at %#RGp spanning %u pages) at %#RGp\n",
2304 pOut->GCPhysStart, pOut->cPages, pHv->GCPhysHypercallOut));
2305 rcHv = GIM_HV_STATUS_SUCCESS;
2306 }
2307 else
2308 {
2309 rcHv = GIM_HV_STATUS_OPERATION_DENIED;
2310 LogRelMax(10, ("GIM: HyperV: HvHypercallExtGetBootZeroedMem failed to update guest memory. rc=%Rrc\n", rc));
2311 rc = VERR_GIM_HYPERCALL_MEMORY_WRITE_FAILED;
2312 }
2313
2314 *prcHv = rcHv;
2315 return rc;
2316}
2317
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