VirtualBox

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

Last change on this file since 87766 was 87766, checked in by vboxsync, 3 years ago

VMM/TM,VMM/*: Refactored the TM timer APIs to use 'handles' and take a pVM parameter. Only internal callbacks have been updated with a hTimer parameter, so far. bugref:9943

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

© 2023 Oracle
ContactPrivacy policyTerms of Use