VirtualBox

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

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

VMM: Added SSM_GET_ENUM32_RET and made the VMM code use it and the volatile getters. bugref:9218

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

© 2023 Oracle
ContactPrivacy policyTerms of Use