VirtualBox

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

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

(C) year

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