VirtualBox

source: vbox/trunk/src/VBox/Devices/VMMDev/VMMDev.cpp@ 60404

Last change on this file since 60404 was 60396, checked in by vboxsync, 8 years ago

VMMDev,PDM,HM: Changed the VMMDev heap interface a little so HM can init without the fake PCI BIOS code having run.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 162.8 KB
Line 
1/* $Id: VMMDev.cpp 60396 2016-04-08 16:17:15Z vboxsync $ */
2/** @file
3 * VMMDev - Guest <-> VMM/Host communication device.
4 */
5
6/*
7 * Copyright (C) 2006-2015 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/** @page pg_vmmdev The VMM Device.
19 *
20 * The VMM device is a custom hardware device emulation for communicating with
21 * the guest additions.
22 *
23 * Whenever host wants to inform guest about something an IRQ notification will
24 * be raised.
25 *
26 * VMMDev PDM interface will contain the guest notification method.
27 *
28 * There is a 32 bit event mask which will be read by guest on an interrupt. A
29 * non zero bit in the mask means that the specific event occurred and requires
30 * processing on guest side.
31 *
32 * After reading the event mask guest must issue a generic request
33 * AcknowlegdeEvents.
34 *
35 * IRQ line is set to 1 (request) if there are unprocessed events, that is the
36 * event mask is not zero.
37 *
38 * After receiving an interrupt and checking event mask, the guest must process
39 * events using the event specific mechanism.
40 *
41 * That is if mouse capabilities were changed, guest will use
42 * VMMDev_GetMouseStatus generic request.
43 *
44 * Event mask is only a set of flags indicating that guest must proceed with a
45 * procedure.
46 *
47 * Unsupported events are therefore ignored. The guest additions must inform
48 * host which events they want to receive, to avoid unnecessary IRQ processing.
49 * By default no events are signalled to guest.
50 *
51 * This seems to be fast method. It requires only one context switch for an
52 * event processing.
53 *
54 *
55 * @section sec_vmmdev_heartbeat Heartbeat
56 *
57 * The heartbeat is a feature to monitor whether the guest OS is hung or not.
58 *
59 * The main kernel component of the guest additions, VBoxGuest, sets up a timer
60 * at a frequency returned by VMMDevReq_HeartbeatConfigure
61 * (VMMDevReqHeartbeat::cNsInterval, VMMDEV::cNsHeartbeatInterval) and performs
62 * a VMMDevReq_GuestHeartbeat request every time the timer ticks.
63 *
64 * The host side (VMMDev) arms a timer with a more distant deadline
65 * (VMMDEV::cNsHeartbeatTimeout), twice cNsHeartbeatInterval by default. Each
66 * time a VMMDevReq_GuestHeartbeat request comes in, the timer is rearmed with
67 * the same relative deadline. So, as long as VMMDevReq_GuestHeartbeat comes
68 * when they should, the host timer will never fire.
69 *
70 * When the timer fires, we consider the guest as hung / flatlined / dead.
71 * Currently we only LogRel that, but it's easy to extend this with an event in
72 * Main API.
73 *
74 * Should the guest reawaken at some later point, we LogRel that event and
75 * continue as normal. Again something which would merit an API event.
76 *
77 */
78
79
80/*********************************************************************************************************************************
81* Header Files *
82*********************************************************************************************************************************/
83/* Enable dev_vmm Log3 statements to get IRQ-related logging. */
84#define LOG_GROUP LOG_GROUP_DEV_VMM
85#include <VBox/VMMDev.h>
86#include <VBox/vmm/mm.h>
87#include <VBox/log.h>
88#include <VBox/param.h>
89#include <iprt/path.h>
90#include <iprt/dir.h>
91#include <iprt/file.h>
92#include <VBox/vmm/pgm.h>
93#include <VBox/err.h>
94#include <VBox/vmm/vm.h> /* for VM_IS_EMT */
95#include <VBox/dbg.h>
96#include <VBox/version.h>
97
98#include <iprt/asm.h>
99#include <iprt/asm-amd64-x86.h>
100#include <iprt/assert.h>
101#include <iprt/buildconfig.h>
102#include <iprt/string.h>
103#include <iprt/time.h>
104#ifndef IN_RC
105# include <iprt/mem.h>
106#endif
107#ifdef IN_RING3
108# include <iprt/uuid.h>
109#endif
110
111#include "VMMDevState.h"
112#ifdef VBOX_WITH_HGCM
113# include "VMMDevHGCM.h"
114#endif
115#ifndef VBOX_WITHOUT_TESTING_FEATURES
116# include "VMMDevTesting.h"
117#endif
118
119
120/*********************************************************************************************************************************
121* Defined Constants And Macros *
122*********************************************************************************************************************************/
123#define VMMDEV_INTERFACE_VERSION_IS_1_03(s) \
124 ( RT_HIWORD((s)->guestInfo.interfaceVersion) == 1 \
125 && RT_LOWORD((s)->guestInfo.interfaceVersion) == 3 )
126
127#define VMMDEV_INTERFACE_VERSION_IS_OK(additionsVersion) \
128 ( RT_HIWORD(additionsVersion) == RT_HIWORD(VMMDEV_VERSION) \
129 && RT_LOWORD(additionsVersion) <= RT_LOWORD(VMMDEV_VERSION) )
130
131#define VMMDEV_INTERFACE_VERSION_IS_OLD(additionsVersion) \
132 ( (RT_HIWORD(additionsVersion) < RT_HIWORD(VMMDEV_VERSION) \
133 || ( RT_HIWORD(additionsVersion) == RT_HIWORD(VMMDEV_VERSION) \
134 && RT_LOWORD(additionsVersion) <= RT_LOWORD(VMMDEV_VERSION) ) )
135
136#define VMMDEV_INTERFACE_VERSION_IS_TOO_OLD(additionsVersion) \
137 ( RT_HIWORD(additionsVersion) < RT_HIWORD(VMMDEV_VERSION) )
138
139#define VMMDEV_INTERFACE_VERSION_IS_NEW(additionsVersion) \
140 ( RT_HIWORD(additionsVersion) > RT_HIWORD(VMMDEV_VERSION) \
141 || ( RT_HIWORD(additionsVersion) == RT_HIWORD(VMMDEV_VERSION) \
142 && RT_LOWORD(additionsVersion) > RT_LOWORD(VMMDEV_VERSION) ) )
143
144/** The saved state version. */
145#define VMMDEV_SAVED_STATE_VERSION VMMDEV_SAVED_STATE_VERSION_HEARTBEAT
146/** The saved state version with heartbeat state. */
147#define VMMDEV_SAVED_STATE_VERSION_HEARTBEAT 16
148/** The saved state version without heartbeat state. */
149#define VMMDEV_SAVED_STATE_VERSION_NO_HEARTBEAT 15
150/** The saved state version which is missing the guest facility statuses. */
151#define VMMDEV_SAVED_STATE_VERSION_MISSING_FACILITY_STATUSES 14
152/** The saved state version which is missing the guestInfo2 bits. */
153#define VMMDEV_SAVED_STATE_VERSION_MISSING_GUEST_INFO_2 13
154/** The saved state version used by VirtualBox 3.0.
155 * This doesn't have the config part. */
156#define VMMDEV_SAVED_STATE_VERSION_VBOX_30 11
157/** Default interval in nanoseconds between guest heartbeats.
158 * Used when no HeartbeatInterval is set in CFGM and for setting
159 * HB check timer if the guest's heartbeat frequency is less than 1Hz. */
160#define VMMDEV_HEARTBEAT_DEFAULT_INTERVAL (2U*RT_NS_1SEC_64)
161
162
163#ifndef VBOX_DEVICE_STRUCT_TESTCASE
164
165/* -=-=-=-=- Misc Helpers -=-=-=-=- */
166
167/**
168 * Log information about the Guest Additions.
169 *
170 * @param pGuestInfo The information we've got from the Guest Additions driver.
171 */
172static void vmmdevLogGuestOsInfo(VBoxGuestInfo *pGuestInfo)
173{
174 const char *pszOs;
175 switch (pGuestInfo->osType & ~VBOXOSTYPE_x64)
176 {
177 case VBOXOSTYPE_DOS: pszOs = "DOS"; break;
178 case VBOXOSTYPE_Win31: pszOs = "Windows 3.1"; break;
179 case VBOXOSTYPE_Win9x: pszOs = "Windows 9x"; break;
180 case VBOXOSTYPE_Win95: pszOs = "Windows 95"; break;
181 case VBOXOSTYPE_Win98: pszOs = "Windows 98"; break;
182 case VBOXOSTYPE_WinMe: pszOs = "Windows Me"; break;
183 case VBOXOSTYPE_WinNT: pszOs = "Windows NT"; break;
184 case VBOXOSTYPE_WinNT4: pszOs = "Windows NT4"; break;
185 case VBOXOSTYPE_Win2k: pszOs = "Windows 2k"; break;
186 case VBOXOSTYPE_WinXP: pszOs = "Windows XP"; break;
187 case VBOXOSTYPE_Win2k3: pszOs = "Windows 2k3"; break;
188 case VBOXOSTYPE_WinVista: pszOs = "Windows Vista"; break;
189 case VBOXOSTYPE_Win2k8: pszOs = "Windows 2k8"; break;
190 case VBOXOSTYPE_Win7: pszOs = "Windows 7"; break;
191 case VBOXOSTYPE_Win8: pszOs = "Windows 8"; break;
192 case VBOXOSTYPE_Win2k12_x64 & ~VBOXOSTYPE_x64: pszOs = "Windows 2k12"; break;
193 case VBOXOSTYPE_Win81: pszOs = "Windows 8.1"; break;
194 case VBOXOSTYPE_Win10: pszOs = "Windows 10"; break;
195 case VBOXOSTYPE_OS2: pszOs = "OS/2"; break;
196 case VBOXOSTYPE_OS2Warp3: pszOs = "OS/2 Warp 3"; break;
197 case VBOXOSTYPE_OS2Warp4: pszOs = "OS/2 Warp 4"; break;
198 case VBOXOSTYPE_OS2Warp45: pszOs = "OS/2 Warp 4.5"; break;
199 case VBOXOSTYPE_ECS: pszOs = "OS/2 ECS"; break;
200 case VBOXOSTYPE_OS21x: pszOs = "OS/2 2.1x"; break;
201 case VBOXOSTYPE_Linux: pszOs = "Linux"; break;
202 case VBOXOSTYPE_Linux22: pszOs = "Linux 2.2"; break;
203 case VBOXOSTYPE_Linux24: pszOs = "Linux 2.4"; break;
204 case VBOXOSTYPE_Linux26: pszOs = "Linux >= 2.6"; break;
205 case VBOXOSTYPE_ArchLinux: pszOs = "ArchLinux"; break;
206 case VBOXOSTYPE_Debian: pszOs = "Debian"; break;
207 case VBOXOSTYPE_OpenSUSE: pszOs = "openSUSE"; break;
208 case VBOXOSTYPE_FedoraCore: pszOs = "Fedora"; break;
209 case VBOXOSTYPE_Gentoo: pszOs = "Gentoo"; break;
210 case VBOXOSTYPE_Mandriva: pszOs = "Mandriva"; break;
211 case VBOXOSTYPE_RedHat: pszOs = "RedHat"; break;
212 case VBOXOSTYPE_Turbolinux: pszOs = "TurboLinux"; break;
213 case VBOXOSTYPE_Ubuntu: pszOs = "Ubuntu"; break;
214 case VBOXOSTYPE_Xandros: pszOs = "Xandros"; break;
215 case VBOXOSTYPE_Oracle: pszOs = "Oracle Linux"; break;
216 case VBOXOSTYPE_FreeBSD: pszOs = "FreeBSD"; break;
217 case VBOXOSTYPE_OpenBSD: pszOs = "OpenBSD"; break;
218 case VBOXOSTYPE_NetBSD: pszOs = "NetBSD"; break;
219 case VBOXOSTYPE_Netware: pszOs = "Netware"; break;
220 case VBOXOSTYPE_Solaris: pszOs = "Solaris"; break;
221 case VBOXOSTYPE_OpenSolaris: pszOs = "OpenSolaris"; break;
222 case VBOXOSTYPE_Solaris11_x64 & ~VBOXOSTYPE_x64: pszOs = "Solaris 11"; break;
223 case VBOXOSTYPE_MacOS: pszOs = "Mac OS X"; break;
224 case VBOXOSTYPE_MacOS106: pszOs = "Mac OS X 10.6"; break;
225 case VBOXOSTYPE_MacOS107_x64 & ~VBOXOSTYPE_x64: pszOs = "Mac OS X 10.7"; break;
226 case VBOXOSTYPE_MacOS108_x64 & ~VBOXOSTYPE_x64: pszOs = "Mac OS X 10.8"; break;
227 case VBOXOSTYPE_MacOS109_x64 & ~VBOXOSTYPE_x64: pszOs = "Mac OS X 10.9"; break;
228 case VBOXOSTYPE_MacOS1010_x64 & ~VBOXOSTYPE_x64: pszOs = "Mac OS X 10.10"; break;
229 case VBOXOSTYPE_MacOS1011_x64 & ~VBOXOSTYPE_x64: pszOs = "Mac OS X 10.11"; break;
230 case VBOXOSTYPE_Haiku: pszOs = "Haiku"; break;
231 default: pszOs = "unknown"; break;
232 }
233 LogRel(("VMMDev: Guest Additions information report: Interface = 0x%08X osType = 0x%08X (%s, %u-bit)\n",
234 pGuestInfo->interfaceVersion, pGuestInfo->osType, pszOs,
235 pGuestInfo->osType & VBOXOSTYPE_x64 ? 64 : 32));
236}
237
238/**
239 * Sets the IRQ (raise it or lower it) for 1.03 additions.
240 *
241 * @param pThis The VMMDev state.
242 * @thread Any.
243 * @remarks Must be called owning the critical section.
244 */
245static void vmmdevSetIRQ_Legacy(PVMMDEV pThis)
246{
247 if (pThis->fu32AdditionsOk)
248 {
249 /* Filter unsupported events */
250 uint32_t fEvents = pThis->u32HostEventFlags & pThis->pVMMDevRAMR3->V.V1_03.u32GuestEventMask;
251
252 Log(("vmmdevSetIRQ: fEvents=%#010x, u32HostEventFlags=%#010x, u32GuestEventMask=%#010x.\n",
253 fEvents, pThis->u32HostEventFlags, pThis->pVMMDevRAMR3->V.V1_03.u32GuestEventMask));
254
255 /* Move event flags to VMMDev RAM */
256 pThis->pVMMDevRAMR3->V.V1_03.u32HostEvents = fEvents;
257
258 uint32_t uIRQLevel = 0;
259 if (fEvents)
260 {
261 /* Clear host flags which will be delivered to guest. */
262 pThis->u32HostEventFlags &= ~fEvents;
263 Log(("vmmdevSetIRQ: u32HostEventFlags=%#010x\n", pThis->u32HostEventFlags));
264 uIRQLevel = 1;
265 }
266
267 /* Set IRQ level for pin 0 (see NoWait comment in vmmdevMaybeSetIRQ). */
268 /** @todo make IRQ pin configurable, at least a symbolic constant */
269 PDMDevHlpPCISetIrqNoWait(pThis->pDevIns, 0, uIRQLevel);
270 Log(("vmmdevSetIRQ: IRQ set %d\n", uIRQLevel));
271 }
272 else
273 Log(("vmmdevSetIRQ: IRQ is not generated, guest has not yet reported to us.\n"));
274}
275
276/**
277 * Sets the IRQ if there are events to be delivered.
278 *
279 * @param pThis The VMMDev state.
280 * @thread Any.
281 * @remarks Must be called owning the critical section.
282 */
283static void vmmdevMaybeSetIRQ(PVMMDEV pThis)
284{
285 Log3(("vmmdevMaybeSetIRQ: u32HostEventFlags=%#010x, u32GuestFilterMask=%#010x.\n",
286 pThis->u32HostEventFlags, pThis->u32GuestFilterMask));
287
288 if (pThis->u32HostEventFlags & pThis->u32GuestFilterMask)
289 {
290 /*
291 * Note! No need to wait for the IRQs to be set (if we're not luck
292 * with the locks, etc). It is a notification about something,
293 * which has already happened.
294 */
295 pThis->pVMMDevRAMR3->V.V1_04.fHaveEvents = true;
296 PDMDevHlpPCISetIrqNoWait(pThis->pDevIns, 0, 1);
297 Log3(("vmmdevMaybeSetIRQ: IRQ set.\n"));
298 }
299}
300
301/**
302 * Notifies the guest about new events (@a fAddEvents).
303 *
304 * @param pThis The VMMDev state.
305 * @param fAddEvents New events to add.
306 * @thread Any.
307 * @remarks Must be called owning the critical section.
308 */
309static void vmmdevNotifyGuestWorker(PVMMDEV pThis, uint32_t fAddEvents)
310{
311 Log3(("vmmdevNotifyGuestWorker: fAddEvents=%#010x.\n", fAddEvents));
312 Assert(PDMCritSectIsOwner(&pThis->CritSect));
313
314 if (!VMMDEV_INTERFACE_VERSION_IS_1_03(pThis))
315 {
316 Log3(("vmmdevNotifyGuestWorker: New additions detected.\n"));
317
318 if (pThis->fu32AdditionsOk)
319 {
320 const bool fHadEvents = (pThis->u32HostEventFlags & pThis->u32GuestFilterMask) != 0;
321
322 Log3(("vmmdevNotifyGuestWorker: fHadEvents=%d, u32HostEventFlags=%#010x, u32GuestFilterMask=%#010x.\n",
323 fHadEvents, pThis->u32HostEventFlags, pThis->u32GuestFilterMask));
324
325 pThis->u32HostEventFlags |= fAddEvents;
326
327 if (!fHadEvents)
328 vmmdevMaybeSetIRQ(pThis);
329 }
330 else
331 {
332 pThis->u32HostEventFlags |= fAddEvents;
333 Log(("vmmdevNotifyGuestWorker: IRQ is not generated, guest has not yet reported to us.\n"));
334 }
335 }
336 else
337 {
338 Log3(("vmmdevNotifyGuestWorker: Old additions detected.\n"));
339
340 pThis->u32HostEventFlags |= fAddEvents;
341 vmmdevSetIRQ_Legacy(pThis);
342 }
343}
344
345
346
347/* -=-=-=-=- Interfaces shared with VMMDevHGCM.cpp -=-=-=-=- */
348
349/**
350 * Notifies the guest about new events (@a fAddEvents).
351 *
352 * This is used by VMMDev.cpp as well as VMMDevHGCM.cpp.
353 *
354 * @param pThis The VMMDev state.
355 * @param fAddEvents New events to add.
356 * @thread Any.
357 */
358void VMMDevNotifyGuest(PVMMDEV pThis, uint32_t fAddEvents)
359{
360 Log3(("VMMDevNotifyGuest: fAddEvents=%#010x\n", fAddEvents));
361
362 /*
363 * Only notify the VM when it's running.
364 */
365 VMSTATE enmVMState = PDMDevHlpVMState(pThis->pDevIns);
366/** @todo r=bird: Shouldn't there be more states here? Wouldn't we drop
367 * notifications now when we're in the process of suspending or
368 * similar? */
369 if ( enmVMState == VMSTATE_RUNNING
370 || enmVMState == VMSTATE_RUNNING_LS)
371 {
372 PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
373 vmmdevNotifyGuestWorker(pThis, fAddEvents);
374 PDMCritSectLeave(&pThis->CritSect);
375 }
376}
377
378/**
379 * Code shared by VMMDevReq_CtlGuestFilterMask and HGCM for controlling the
380 * events the guest are interested in.
381 *
382 * @param pThis The VMMDev state.
383 * @param fOrMask Events to add (VMMDEV_EVENT_XXX). Pass 0 for no
384 * change.
385 * @param fNotMask Events to remove (VMMDEV_EVENT_XXX). Pass 0 for no
386 * change.
387 *
388 * @remarks When HGCM will automatically enable VMMDEV_EVENT_HGCM when the guest
389 * starts submitting HGCM requests. Otherwise, the events are
390 * controlled by the guest.
391 */
392void VMMDevCtlSetGuestFilterMask(PVMMDEV pThis, uint32_t fOrMask, uint32_t fNotMask)
393{
394 PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
395
396 const bool fHadEvents = (pThis->u32HostEventFlags & pThis->u32GuestFilterMask) != 0;
397
398 Log(("VMMDevCtlSetGuestFilterMask: fOrMask=%#010x, u32NotMask=%#010x, fHadEvents=%d.\n", fOrMask, fNotMask, fHadEvents));
399 if (fHadEvents)
400 {
401 if (!pThis->fNewGuestFilterMask)
402 pThis->u32NewGuestFilterMask = pThis->u32GuestFilterMask;
403
404 pThis->u32NewGuestFilterMask |= fOrMask;
405 pThis->u32NewGuestFilterMask &= ~fNotMask;
406 pThis->fNewGuestFilterMask = true;
407 }
408 else
409 {
410 pThis->u32GuestFilterMask |= fOrMask;
411 pThis->u32GuestFilterMask &= ~fNotMask;
412 vmmdevMaybeSetIRQ(pThis);
413 }
414
415 PDMCritSectLeave(&pThis->CritSect);
416}
417
418
419
420/* -=-=-=-=- Request processing functions. -=-=-=-=- */
421
422/**
423 * Handles VMMDevReq_ReportGuestInfo.
424 *
425 * @returns VBox status code that the guest should see.
426 * @param pThis The VMMDev instance data.
427 * @param pRequestHeader The header of the request to handle.
428 */
429static int vmmdevReqHandler_ReportGuestInfo(PVMMDEV pThis, VMMDevRequestHeader *pRequestHeader)
430{
431 AssertMsgReturn(pRequestHeader->size == sizeof(VMMDevReportGuestInfo), ("%u\n", pRequestHeader->size), VERR_INVALID_PARAMETER);
432 VBoxGuestInfo const *pInfo = &((VMMDevReportGuestInfo *)pRequestHeader)->guestInfo;
433
434 if (memcmp(&pThis->guestInfo, pInfo, sizeof(*pInfo)) != 0)
435 {
436 /* Make a copy of supplied information. */
437 pThis->guestInfo = *pInfo;
438
439 /* Check additions interface version. */
440 pThis->fu32AdditionsOk = VMMDEV_INTERFACE_VERSION_IS_OK(pThis->guestInfo.interfaceVersion);
441
442 vmmdevLogGuestOsInfo(&pThis->guestInfo);
443
444 if (pThis->pDrv && pThis->pDrv->pfnUpdateGuestInfo)
445 pThis->pDrv->pfnUpdateGuestInfo(pThis->pDrv, &pThis->guestInfo);
446 }
447
448 if (!pThis->fu32AdditionsOk)
449 return VERR_VERSION_MISMATCH;
450
451 /* Clear our IRQ in case it was high for whatever reason. */
452 PDMDevHlpPCISetIrqNoWait(pThis->pDevIns, 0, 0);
453
454 return VINF_SUCCESS;
455}
456
457
458/**
459 * Handles VMMDevReq_GuestHeartbeat.
460 *
461 * @returns VBox status code that the guest should see.
462 * @param pThis The VMMDev instance data.
463 */
464static int vmmDevReqHandler_GuestHeartbeat(PVMMDEV pThis)
465{
466 int rc;
467 if (pThis->fHeartbeatActive)
468 {
469 uint64_t const nsNowTS = TMTimerGetNano(pThis->pFlatlinedTimer);
470 if (!pThis->fFlatlined)
471 { /* likely */ }
472 else
473 {
474 LogRel(("VMMDev: GuestHeartBeat: Guest is alive (gone %'llu ns)\n", nsNowTS - pThis->nsLastHeartbeatTS));
475 ASMAtomicWriteBool(&pThis->fFlatlined, false);
476 }
477 ASMAtomicWriteU64(&pThis->nsLastHeartbeatTS, nsNowTS);
478
479 /* Postpone (or restart if we missed a beat) the timeout timer. */
480 rc = TMTimerSetNano(pThis->pFlatlinedTimer, pThis->cNsHeartbeatTimeout);
481 }
482 else
483 rc = VINF_SUCCESS;
484 return rc;
485}
486
487
488/**
489 * Timer that fires when where have been no heartbeats for a given time.
490 *
491 * @remarks Does not take the VMMDev critsect.
492 */
493static DECLCALLBACK(void) vmmDevHeartbeatFlatlinedTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
494{
495 PVMMDEV pThis = (PVMMDEV)pvUser;
496 if (pThis->fHeartbeatActive)
497 {
498 uint64_t cNsElapsed = TMTimerGetNano(pTimer) - pThis->nsLastHeartbeatTS;
499 if ( !pThis->fFlatlined
500 && cNsElapsed >= pThis->cNsHeartbeatInterval)
501 {
502 LogRel(("VMMDev: vmmDevHeartbeatFlatlinedTimer: Guest seems to be unresponsive. Last heartbeat received %RU64 seconds ago\n",
503 cNsElapsed / RT_NS_1SEC));
504 ASMAtomicWriteBool(&pThis->fFlatlined, true);
505 }
506 }
507}
508
509
510/**
511 * Handles VMMDevReq_HeartbeatConfigure.
512 *
513 * @returns VBox status code that the guest should see.
514 * @param pThis The VMMDev instance data.
515 * @param pReqHdr The header of the request to handle.
516 */
517static int vmmDevReqHandler_HeartbeatConfigure(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
518{
519 AssertMsgReturn(pReqHdr->size == sizeof(VMMDevReqHeartbeat), ("%u\n", pReqHdr->size), VERR_INVALID_PARAMETER);
520 VMMDevReqHeartbeat *pReq = (VMMDevReqHeartbeat *)pReqHdr;
521 int rc;
522
523 pReq->cNsInterval = pThis->cNsHeartbeatInterval;
524
525 if (pReq->fEnabled != pThis->fHeartbeatActive)
526 {
527 ASMAtomicWriteBool(&pThis->fHeartbeatActive, pReq->fEnabled);
528 if (pReq->fEnabled)
529 {
530 /*
531 * Activate the heartbeat monitor.
532 */
533 pThis->nsLastHeartbeatTS = TMTimerGetNano(pThis->pFlatlinedTimer);
534 rc = TMTimerSetNano(pThis->pFlatlinedTimer, pThis->cNsHeartbeatTimeout);
535 if (RT_SUCCESS(rc))
536 LogRel(("VMMDev: Heartbeat flatline timer set to trigger after %'RU64 ns\n", pThis->cNsHeartbeatTimeout));
537 else
538 LogRel(("VMMDev: Error starting flatline timer (heartbeat): %Rrc\n", rc));
539 }
540 else
541 {
542 /*
543 * Deactivate the heartbeat monitor.
544 */
545 rc = TMTimerStop(pThis->pFlatlinedTimer);
546 LogRel(("VMMDev: Heartbeat checking timer has been stopped (rc=%Rrc)\n", rc));
547 }
548 }
549 else
550 {
551 LogRel(("VMMDev: vmmDevReqHandler_HeartbeatConfigure: No change (fHeartbeatActive=%RTbool).\n", pThis->fHeartbeatActive));
552 rc = VINF_SUCCESS;
553 }
554
555 return rc;
556}
557
558
559/**
560 * Validates a publisher tag.
561 *
562 * @returns true / false.
563 * @param pszTag Tag to validate.
564 */
565static bool vmmdevReqIsValidPublisherTag(const char *pszTag)
566{
567 /* Note! This character set is also found in Config.kmk. */
568 static char const s_szValidChars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz()[]{}+-.,";
569
570 while (*pszTag != '\0')
571 {
572 if (!strchr(s_szValidChars, *pszTag))
573 return false;
574 pszTag++;
575 }
576 return true;
577}
578
579
580/**
581 * Validates a build tag.
582 *
583 * @returns true / false.
584 * @param pszTag Tag to validate.
585 */
586static bool vmmdevReqIsValidBuildTag(const char *pszTag)
587{
588 int cchPrefix;
589 if (!strncmp(pszTag, "RC", 2))
590 cchPrefix = 2;
591 else if (!strncmp(pszTag, "BETA", 4))
592 cchPrefix = 4;
593 else if (!strncmp(pszTag, "ALPHA", 5))
594 cchPrefix = 5;
595 else
596 return false;
597
598 if (pszTag[cchPrefix] == '\0')
599 return true;
600
601 uint8_t u8;
602 int rc = RTStrToUInt8Full(&pszTag[cchPrefix], 10, &u8);
603 return rc == VINF_SUCCESS;
604}
605
606
607/**
608 * Handles VMMDevReq_ReportGuestInfo2.
609 *
610 * @returns VBox status code that the guest should see.
611 * @param pThis The VMMDev instance data.
612 * @param pReqHdr The header of the request to handle.
613 */
614static int vmmdevReqHandler_ReportGuestInfo2(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
615{
616 AssertMsgReturn(pReqHdr->size == sizeof(VMMDevReportGuestInfo2), ("%u\n", pReqHdr->size), VERR_INVALID_PARAMETER);
617 VBoxGuestInfo2 const *pInfo2 = &((VMMDevReportGuestInfo2 *)pReqHdr)->guestInfo;
618
619 LogRel(("VMMDev: Guest Additions information report: Version %d.%d.%d r%d '%.*s'\n",
620 pInfo2->additionsMajor, pInfo2->additionsMinor, pInfo2->additionsBuild,
621 pInfo2->additionsRevision, sizeof(pInfo2->szName), pInfo2->szName));
622
623 /* The interface was introduced in 3.2 and will definitely not be
624 backported beyond 3.0 (bird). */
625 AssertMsgReturn(pInfo2->additionsMajor >= 3,
626 ("%u.%u.%u\n", pInfo2->additionsMajor, pInfo2->additionsMinor, pInfo2->additionsBuild),
627 VERR_INVALID_PARAMETER);
628
629 /* The version must fit in a full version compression. */
630 uint32_t uFullVersion = VBOX_FULL_VERSION_MAKE(pInfo2->additionsMajor, pInfo2->additionsMinor, pInfo2->additionsBuild);
631 AssertMsgReturn( VBOX_FULL_VERSION_GET_MAJOR(uFullVersion) == pInfo2->additionsMajor
632 && VBOX_FULL_VERSION_GET_MINOR(uFullVersion) == pInfo2->additionsMinor
633 && VBOX_FULL_VERSION_GET_BUILD(uFullVersion) == pInfo2->additionsBuild,
634 ("%u.%u.%u\n", pInfo2->additionsMajor, pInfo2->additionsMinor, pInfo2->additionsBuild),
635 VERR_OUT_OF_RANGE);
636
637 /*
638 * Validate the name.
639 * Be less strict towards older additions (< v4.1.50).
640 */
641 AssertCompile(sizeof(pThis->guestInfo2.szName) == sizeof(pInfo2->szName));
642 AssertReturn(RTStrEnd(pInfo2->szName, sizeof(pInfo2->szName)) != NULL, VERR_INVALID_PARAMETER);
643 const char *pszName = pInfo2->szName;
644
645 /* The version number which shouldn't be there. */
646 char szTmp[sizeof(pInfo2->szName)];
647 size_t cchStart = RTStrPrintf(szTmp, sizeof(szTmp), "%u.%u.%u", pInfo2->additionsMajor, pInfo2->additionsMinor, pInfo2->additionsBuild);
648 AssertMsgReturn(!strncmp(pszName, szTmp, cchStart), ("%s != %s\n", pszName, szTmp), VERR_INVALID_PARAMETER);
649 pszName += cchStart;
650
651 /* Now we can either have nothing or a build tag or/and a publisher tag. */
652 if (*pszName != '\0')
653 {
654 const char *pszRelaxedName = "";
655 bool const fStrict = pInfo2->additionsMajor > 4
656 || (pInfo2->additionsMajor == 4 && pInfo2->additionsMinor > 1)
657 || (pInfo2->additionsMajor == 4 && pInfo2->additionsMinor == 1 && pInfo2->additionsBuild >= 50);
658 bool fOk = false;
659 if (*pszName == '_')
660 {
661 pszName++;
662 strcpy(szTmp, pszName);
663 char *pszTag2 = strchr(szTmp, '_');
664 if (!pszTag2)
665 {
666 fOk = vmmdevReqIsValidBuildTag(szTmp)
667 || vmmdevReqIsValidPublisherTag(szTmp);
668 }
669 else
670 {
671 *pszTag2++ = '\0';
672 fOk = vmmdevReqIsValidBuildTag(szTmp);
673 if (fOk)
674 {
675 fOk = vmmdevReqIsValidPublisherTag(pszTag2);
676 if (!fOk)
677 pszRelaxedName = szTmp;
678 }
679 }
680 }
681
682 if (!fOk)
683 {
684 AssertLogRelMsgReturn(!fStrict, ("%s", pszName), VERR_INVALID_PARAMETER);
685
686 /* non-strict mode, just zap the extra stuff. */
687 LogRel(("VMMDev: ReportGuestInfo2: Ignoring unparsable version name bits: '%s' -> '%s'.\n", pszName, pszRelaxedName));
688 pszName = pszRelaxedName;
689 }
690 }
691
692 /*
693 * Save the info and tell Main or whoever is listening.
694 */
695 pThis->guestInfo2.uFullVersion = uFullVersion;
696 pThis->guestInfo2.uRevision = pInfo2->additionsRevision;
697 pThis->guestInfo2.fFeatures = pInfo2->additionsFeatures;
698 strcpy(pThis->guestInfo2.szName, pszName);
699
700 if (pThis->pDrv && pThis->pDrv->pfnUpdateGuestInfo2)
701 pThis->pDrv->pfnUpdateGuestInfo2(pThis->pDrv, uFullVersion, pszName, pInfo2->additionsRevision, pInfo2->additionsFeatures);
702
703 /* Clear our IRQ in case it was high for whatever reason. */
704 PDMDevHlpPCISetIrqNoWait(pThis->pDevIns, 0, 0);
705
706 return VINF_SUCCESS;
707}
708
709
710/**
711 * Allocates a new facility status entry, initializing it to inactive.
712 *
713 * @returns Pointer to a facility status entry on success, NULL on failure
714 * (table full).
715 * @param pThis The VMMDev instance data.
716 * @param enmFacility The facility type code.
717 * @param fFixed This is set when allocating the standard entries
718 * from the constructor.
719 * @param pTimeSpecNow Optionally giving the entry timestamp to use (ctor).
720 */
721static PVMMDEVFACILITYSTATUSENTRY
722vmmdevAllocFacilityStatusEntry(PVMMDEV pThis, VBoxGuestFacilityType enmFacility, bool fFixed, PCRTTIMESPEC pTimeSpecNow)
723{
724 /* If full, expunge one inactive entry. */
725 if (pThis->cFacilityStatuses == RT_ELEMENTS(pThis->aFacilityStatuses))
726 {
727 uint32_t i = pThis->cFacilityStatuses;
728 while (i-- > 0)
729 {
730 if ( pThis->aFacilityStatuses[i].enmStatus == VBoxGuestFacilityStatus_Inactive
731 && !pThis->aFacilityStatuses[i].fFixed)
732 {
733 pThis->cFacilityStatuses--;
734 int cToMove = pThis->cFacilityStatuses - i;
735 if (cToMove)
736 memmove(&pThis->aFacilityStatuses[i], &pThis->aFacilityStatuses[i + 1],
737 cToMove * sizeof(pThis->aFacilityStatuses[i]));
738 RT_ZERO(pThis->aFacilityStatuses[pThis->cFacilityStatuses]);
739 break;
740 }
741 }
742
743 if (pThis->cFacilityStatuses == RT_ELEMENTS(pThis->aFacilityStatuses))
744 return NULL;
745 }
746
747 /* Find location in array (it's sorted). */
748 uint32_t i = pThis->cFacilityStatuses;
749 while (i-- > 0)
750 if ((uint32_t)pThis->aFacilityStatuses[i].enmFacility < (uint32_t)enmFacility)
751 break;
752 i++;
753
754 /* Move. */
755 int cToMove = pThis->cFacilityStatuses - i;
756 if (cToMove > 0)
757 memmove(&pThis->aFacilityStatuses[i + 1], &pThis->aFacilityStatuses[i],
758 cToMove * sizeof(pThis->aFacilityStatuses[i]));
759 pThis->cFacilityStatuses++;
760
761 /* Initialize. */
762 pThis->aFacilityStatuses[i].enmFacility = enmFacility;
763 pThis->aFacilityStatuses[i].enmStatus = VBoxGuestFacilityStatus_Inactive;
764 pThis->aFacilityStatuses[i].fFixed = fFixed;
765 pThis->aFacilityStatuses[i].afPadding[0] = 0;
766 pThis->aFacilityStatuses[i].afPadding[1] = 0;
767 pThis->aFacilityStatuses[i].afPadding[2] = 0;
768 pThis->aFacilityStatuses[i].fFlags = 0;
769 if (pTimeSpecNow)
770 pThis->aFacilityStatuses[i].TimeSpecTS = *pTimeSpecNow;
771 else
772 RTTimeSpecSetNano(&pThis->aFacilityStatuses[i].TimeSpecTS, 0);
773
774 return &pThis->aFacilityStatuses[i];
775}
776
777
778/**
779 * Gets a facility status entry, allocating a new one if not already present.
780 *
781 * @returns Pointer to a facility status entry on success, NULL on failure
782 * (table full).
783 * @param pThis The VMMDev instance data.
784 * @param enmFacility The facility type code.
785 */
786static PVMMDEVFACILITYSTATUSENTRY vmmdevGetFacilityStatusEntry(PVMMDEV pThis, VBoxGuestFacilityType enmFacility)
787{
788 /** @todo change to binary search. */
789 uint32_t i = pThis->cFacilityStatuses;
790 while (i-- > 0)
791 {
792 if (pThis->aFacilityStatuses[i].enmFacility == enmFacility)
793 return &pThis->aFacilityStatuses[i];
794 if ((uint32_t)pThis->aFacilityStatuses[i].enmFacility < (uint32_t)enmFacility)
795 break;
796 }
797 return vmmdevAllocFacilityStatusEntry(pThis, enmFacility, false /*fFixed*/, NULL);
798}
799
800
801/**
802 * Handles VMMDevReq_ReportGuestStatus.
803 *
804 * @returns VBox status code that the guest should see.
805 * @param pThis The VMMDev instance data.
806 * @param pReqHdr The header of the request to handle.
807 */
808static int vmmdevReqHandler_ReportGuestStatus(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
809{
810 /*
811 * Validate input.
812 */
813 AssertMsgReturn(pReqHdr->size == sizeof(VMMDevReportGuestStatus), ("%u\n", pReqHdr->size), VERR_INVALID_PARAMETER);
814 VBoxGuestStatus *pStatus = &((VMMDevReportGuestStatus *)pReqHdr)->guestStatus;
815 AssertMsgReturn( pStatus->facility > VBoxGuestFacilityType_Unknown
816 && pStatus->facility <= VBoxGuestFacilityType_All,
817 ("%d\n", pStatus->facility),
818 VERR_INVALID_PARAMETER);
819 AssertMsgReturn(pStatus->status == (VBoxGuestFacilityStatus)(uint16_t)pStatus->status,
820 ("%#x (%u)\n", pStatus->status, pStatus->status),
821 VERR_OUT_OF_RANGE);
822
823 /*
824 * Do the update.
825 */
826 RTTIMESPEC Now;
827 RTTimeNow(&Now);
828 if (pStatus->facility == VBoxGuestFacilityType_All)
829 {
830 uint32_t i = pThis->cFacilityStatuses;
831 while (i-- > 0)
832 {
833 pThis->aFacilityStatuses[i].TimeSpecTS = Now;
834 pThis->aFacilityStatuses[i].enmStatus = pStatus->status;
835 pThis->aFacilityStatuses[i].fFlags = pStatus->flags;
836 }
837 }
838 else
839 {
840 PVMMDEVFACILITYSTATUSENTRY pEntry = vmmdevGetFacilityStatusEntry(pThis, pStatus->facility);
841 if (!pEntry)
842 {
843 LogRelMax(10, ("VMMDev: Facility table is full - facility=%u status=%u\n", pStatus->facility, pStatus->status));
844 return VERR_OUT_OF_RESOURCES;
845 }
846
847 pEntry->TimeSpecTS = Now;
848 pEntry->enmStatus = pStatus->status;
849 pEntry->fFlags = pStatus->flags;
850 }
851
852 if (pThis->pDrv && pThis->pDrv->pfnUpdateGuestStatus)
853 pThis->pDrv->pfnUpdateGuestStatus(pThis->pDrv, pStatus->facility, pStatus->status, pStatus->flags, &Now);
854
855 return VINF_SUCCESS;
856}
857
858
859/**
860 * Handles VMMDevReq_ReportGuestUserState.
861 *
862 * @returns VBox status code that the guest should see.
863 * @param pThis The VMMDev instance data.
864 * @param pReqHdr The header of the request to handle.
865 */
866static int vmmdevReqHandler_ReportGuestUserState(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
867{
868 /*
869 * Validate input.
870 */
871 VMMDevReportGuestUserState *pReq = (VMMDevReportGuestUserState *)pReqHdr;
872 AssertMsgReturn(pReq->header.size >= sizeof(*pReq), ("%u\n", pReqHdr->size), VERR_INVALID_PARAMETER);
873
874 if ( pThis->pDrv
875 && pThis->pDrv->pfnUpdateGuestUserState)
876 {
877 /* Play safe. */
878 AssertReturn(pReq->header.size <= _2K, VERR_TOO_MUCH_DATA);
879 AssertReturn(pReq->status.cbUser <= 256, VERR_TOO_MUCH_DATA);
880 AssertReturn(pReq->status.cbDomain <= 256, VERR_TOO_MUCH_DATA);
881 AssertReturn(pReq->status.cbDetails <= _1K, VERR_TOO_MUCH_DATA);
882
883 /* pbDynamic marks the beginning of the struct's dynamically
884 * allocated data area. */
885 uint8_t *pbDynamic = (uint8_t *)&pReq->status.szUser;
886 uint32_t cbLeft = pReqHdr->size - RT_OFFSETOF(VMMDevReportGuestUserState, status.szUser);
887
888 /* The user. */
889 AssertReturn(pReq->status.cbUser > 0, VERR_INVALID_PARAMETER); /* User name is required. */
890 AssertReturn(pReq->status.cbUser <= cbLeft, VERR_INVALID_PARAMETER);
891 const char *pszUser = (const char *)pbDynamic;
892 AssertReturn(RTStrEnd(pszUser, pReq->status.cbUser), VERR_INVALID_PARAMETER);
893 int rc = RTStrValidateEncoding(pszUser);
894 AssertRCReturn(rc, rc);
895
896 /* Advance to the next field. */
897 pbDynamic += pReq->status.cbUser;
898 cbLeft -= pReq->status.cbUser;
899
900 /* pszDomain can be NULL. */
901 AssertReturn(pReq->status.cbDomain <= cbLeft, VERR_INVALID_PARAMETER);
902 const char *pszDomain = NULL;
903 if (pReq->status.cbDomain)
904 {
905 pszDomain = (const char *)pbDynamic;
906 AssertReturn(RTStrEnd(pszDomain, pReq->status.cbDomain), VERR_INVALID_PARAMETER);
907 rc = RTStrValidateEncoding(pszDomain);
908 AssertRCReturn(rc, rc);
909
910 /* Advance to the next field. */
911 pbDynamic += pReq->status.cbDomain;
912 cbLeft -= pReq->status.cbDomain;
913 }
914
915 /* pbDetails can be NULL. */
916 const uint8_t *pbDetails = NULL;
917 AssertReturn(pReq->status.cbDetails <= cbLeft, VERR_INVALID_PARAMETER);
918 if (pReq->status.cbDetails > 0)
919 pbDetails = pbDynamic;
920
921 pThis->pDrv->pfnUpdateGuestUserState(pThis->pDrv, pszUser, pszDomain, (uint32_t)pReq->status.state,
922 pbDetails, pReq->status.cbDetails);
923 }
924
925 return VINF_SUCCESS;
926}
927
928
929/**
930 * Handles VMMDevReq_ReportGuestCapabilities.
931 *
932 * @returns VBox status code that the guest should see.
933 * @param pThis The VMMDev instance data.
934 * @param pReqHdr The header of the request to handle.
935 */
936static int vmmdevReqHandler_ReportGuestCapabilities(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
937{
938 VMMDevReqGuestCapabilities *pReq = (VMMDevReqGuestCapabilities *)pReqHdr;
939 AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
940
941 /* Enable VMMDEV_GUEST_SUPPORTS_GRAPHICS automatically for guests using the old
942 * request to report their capabilities.
943 */
944 const uint32_t fu32Caps = pReq->caps | VMMDEV_GUEST_SUPPORTS_GRAPHICS;
945
946 if (pThis->guestCaps != fu32Caps)
947 {
948 /* make a copy of supplied information */
949 pThis->guestCaps = fu32Caps;
950
951 LogRel(("VMMDev: Guest Additions capability report (legacy): (0x%x) seamless: %s, hostWindowMapping: %s, graphics: yes\n",
952 fu32Caps,
953 fu32Caps & VMMDEV_GUEST_SUPPORTS_SEAMLESS ? "yes" : "no",
954 fu32Caps & VMMDEV_GUEST_SUPPORTS_GUEST_HOST_WINDOW_MAPPING ? "yes" : "no"));
955
956 if (pThis->pDrv && pThis->pDrv->pfnUpdateGuestCapabilities)
957 pThis->pDrv->pfnUpdateGuestCapabilities(pThis->pDrv, fu32Caps);
958 }
959 return VINF_SUCCESS;
960}
961
962
963/**
964 * Handles VMMDevReq_SetGuestCapabilities.
965 *
966 * @returns VBox status code that the guest should see.
967 * @param pThis The VMMDev instance data.
968 * @param pReqHdr The header of the request to handle.
969 */
970static int vmmdevReqHandler_SetGuestCapabilities(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
971{
972 VMMDevReqGuestCapabilities2 *pReq = (VMMDevReqGuestCapabilities2 *)pReqHdr;
973 AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
974
975 uint32_t fu32Caps = pThis->guestCaps;
976 fu32Caps |= pReq->u32OrMask;
977 fu32Caps &= ~pReq->u32NotMask;
978
979 LogRel(("VMMDev: Guest Additions capability report: (%#x -> %#x) seamless: %s, hostWindowMapping: %s, graphics: %s\n",
980 pThis->guestCaps, fu32Caps,
981 fu32Caps & VMMDEV_GUEST_SUPPORTS_SEAMLESS ? "yes" : "no",
982 fu32Caps & VMMDEV_GUEST_SUPPORTS_GUEST_HOST_WINDOW_MAPPING ? "yes" : "no",
983 fu32Caps & VMMDEV_GUEST_SUPPORTS_GRAPHICS ? "yes" : "no"));
984
985 pThis->guestCaps = fu32Caps;
986
987 if (pThis->pDrv && pThis->pDrv->pfnUpdateGuestCapabilities)
988 pThis->pDrv->pfnUpdateGuestCapabilities(pThis->pDrv, fu32Caps);
989
990 return VINF_SUCCESS;
991}
992
993
994/**
995 * Handles VMMDevReq_GetMouseStatus.
996 *
997 * @returns VBox status code that the guest should see.
998 * @param pThis The VMMDev instance data.
999 * @param pReqHdr The header of the request to handle.
1000 */
1001static int vmmdevReqHandler_GetMouseStatus(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
1002{
1003 VMMDevReqMouseStatus *pReq = (VMMDevReqMouseStatus *)pReqHdr;
1004 AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
1005
1006 pReq->mouseFeatures = pThis->mouseCapabilities
1007 & VMMDEV_MOUSE_MASK;
1008 pReq->pointerXPos = pThis->mouseXAbs;
1009 pReq->pointerYPos = pThis->mouseYAbs;
1010 LogRel2(("VMMDev: vmmdevReqHandler_GetMouseStatus: mouseFeatures=%#x, xAbs=%d, yAbs=%d\n",
1011 pReq->mouseFeatures, pReq->pointerXPos, pReq->pointerYPos));
1012 return VINF_SUCCESS;
1013}
1014
1015
1016/**
1017 * Handles VMMDevReq_SetMouseStatus.
1018 *
1019 * @returns VBox status code that the guest should see.
1020 * @param pThis The VMMDev instance data.
1021 * @param pReqHdr The header of the request to handle.
1022 */
1023static int vmmdevReqHandler_SetMouseStatus(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
1024{
1025 VMMDevReqMouseStatus *pReq = (VMMDevReqMouseStatus *)pReqHdr;
1026 AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
1027
1028 LogRelFlow(("VMMDev: vmmdevReqHandler_SetMouseStatus: mouseFeatures=%#x\n", pReq->mouseFeatures));
1029
1030 bool fNotify = false;
1031 if ( (pReq->mouseFeatures & VMMDEV_MOUSE_NOTIFY_HOST_MASK)
1032 != ( pThis->mouseCapabilities
1033 & VMMDEV_MOUSE_NOTIFY_HOST_MASK))
1034 fNotify = true;
1035
1036 pThis->mouseCapabilities &= ~VMMDEV_MOUSE_GUEST_MASK;
1037 pThis->mouseCapabilities |= (pReq->mouseFeatures & VMMDEV_MOUSE_GUEST_MASK);
1038
1039 LogRelFlow(("VMMDev: vmmdevReqHandler_SetMouseStatus: New host capabilities: %#x\n", pThis->mouseCapabilities));
1040
1041 /*
1042 * Notify connector if something changed.
1043 */
1044 if (fNotify)
1045 {
1046 LogRelFlow(("VMMDev: vmmdevReqHandler_SetMouseStatus: Notifying connector\n"));
1047 pThis->pDrv->pfnUpdateMouseCapabilities(pThis->pDrv, pThis->mouseCapabilities);
1048 }
1049
1050 return VINF_SUCCESS;
1051}
1052
1053static int vmmdevVerifyPointerShape(VMMDevReqMousePointer *pReq)
1054{
1055 /* Should be enough for most mouse pointers. */
1056 if (pReq->width > 8192 || pReq->height > 8192)
1057 return VERR_INVALID_PARAMETER;
1058
1059 uint32_t cbShape = (pReq->width + 7) / 8 * pReq->height; /* size of the AND mask */
1060 cbShape = ((cbShape + 3) & ~3) + pReq->width * 4 * pReq->height; /* + gap + size of the XOR mask */
1061 if (RT_UOFFSETOF(VMMDevReqMousePointer, pointerData) + cbShape > pReq->header.size)
1062 return VERR_INVALID_PARAMETER;
1063
1064 return VINF_SUCCESS;
1065}
1066
1067/**
1068 * Handles VMMDevReq_SetPointerShape.
1069 *
1070 * @returns VBox status code that the guest should see.
1071 * @param pThis The VMMDev instance data.
1072 * @param pReqHdr The header of the request to handle.
1073 */
1074static int vmmdevReqHandler_SetPointerShape(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
1075{
1076 VMMDevReqMousePointer *pReq = (VMMDevReqMousePointer *)pReqHdr;
1077 if (pReq->header.size < sizeof(*pReq))
1078 {
1079 AssertMsg(pReq->header.size == 0x10028 && pReq->header.version == 10000, /* don't complain about legacy!!! */
1080 ("VMMDev mouse shape structure has invalid size %d (%#x) version=%d!\n",
1081 pReq->header.size, pReq->header.size, pReq->header.version));
1082 return VERR_INVALID_PARAMETER;
1083 }
1084
1085 bool fVisible = RT_BOOL(pReq->fFlags & VBOX_MOUSE_POINTER_VISIBLE);
1086 bool fAlpha = RT_BOOL(pReq->fFlags & VBOX_MOUSE_POINTER_ALPHA);
1087 bool fShape = RT_BOOL(pReq->fFlags & VBOX_MOUSE_POINTER_SHAPE);
1088
1089 Log(("VMMDevReq_SetPointerShape: visible: %d, alpha: %d, shape = %d, width: %d, height: %d\n",
1090 fVisible, fAlpha, fShape, pReq->width, pReq->height));
1091
1092 if (pReq->header.size == sizeof(VMMDevReqMousePointer))
1093 {
1094 /* The guest did not provide the shape actually. */
1095 fShape = false;
1096 }
1097
1098 /* forward call to driver */
1099 if (fShape)
1100 {
1101 int rc = vmmdevVerifyPointerShape(pReq);
1102 if (RT_FAILURE(rc))
1103 return rc;
1104
1105 pThis->pDrv->pfnUpdatePointerShape(pThis->pDrv,
1106 fVisible,
1107 fAlpha,
1108 pReq->xHot, pReq->yHot,
1109 pReq->width, pReq->height,
1110 pReq->pointerData);
1111 }
1112 else
1113 {
1114 pThis->pDrv->pfnUpdatePointerShape(pThis->pDrv,
1115 fVisible,
1116 0,
1117 0, 0,
1118 0, 0,
1119 NULL);
1120 }
1121
1122 pThis->fHostCursorRequested = fVisible;
1123 return VINF_SUCCESS;
1124}
1125
1126
1127/**
1128 * Handles VMMDevReq_GetHostTime.
1129 *
1130 * @returns VBox status code that the guest should see.
1131 * @param pThis The VMMDev instance data.
1132 * @param pReqHdr The header of the request to handle.
1133 */
1134static int vmmdevReqHandler_GetHostTime(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
1135{
1136 VMMDevReqHostTime *pReq = (VMMDevReqHostTime *)pReqHdr;
1137 AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
1138
1139 if (RT_LIKELY(!pThis->fGetHostTimeDisabled))
1140 {
1141 RTTIMESPEC now;
1142 pReq->time = RTTimeSpecGetMilli(PDMDevHlpTMUtcNow(pThis->pDevIns, &now));
1143 return VINF_SUCCESS;
1144 }
1145 return VERR_NOT_SUPPORTED;
1146}
1147
1148
1149/**
1150 * Handles VMMDevReq_GetHypervisorInfo.
1151 *
1152 * @returns VBox status code that the guest should see.
1153 * @param pThis The VMMDev instance data.
1154 * @param pReqHdr The header of the request to handle.
1155 */
1156static int vmmdevReqHandler_GetHypervisorInfo(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
1157{
1158 VMMDevReqHypervisorInfo *pReq = (VMMDevReqHypervisorInfo *)pReqHdr;
1159 AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
1160
1161 return PGMR3MappingsSize(PDMDevHlpGetVM(pThis->pDevIns), &pReq->hypervisorSize);
1162}
1163
1164
1165/**
1166 * Handles VMMDevReq_SetHypervisorInfo.
1167 *
1168 * @returns VBox status code that the guest should see.
1169 * @param pThis The VMMDev instance data.
1170 * @param pReqHdr The header of the request to handle.
1171 */
1172static int vmmdevReqHandler_SetHypervisorInfo(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
1173{
1174 VMMDevReqHypervisorInfo *pReq = (VMMDevReqHypervisorInfo *)pReqHdr;
1175 AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
1176
1177 int rc;
1178 PVM pVM = PDMDevHlpGetVM(pThis->pDevIns);
1179 if (pReq->hypervisorStart == 0)
1180 rc = PGMR3MappingsUnfix(pVM);
1181 else
1182 {
1183 /* only if the client has queried the size before! */
1184 uint32_t cbMappings;
1185 rc = PGMR3MappingsSize(pVM, &cbMappings);
1186 if (RT_SUCCESS(rc) && pReq->hypervisorSize == cbMappings)
1187 {
1188 /* new reservation */
1189 rc = PGMR3MappingsFix(pVM, pReq->hypervisorStart, pReq->hypervisorSize);
1190 LogRel(("VMMDev: Guest reported fixed hypervisor window at 0%010x LB %#x (rc=%Rrc)\n",
1191 pReq->hypervisorStart, pReq->hypervisorSize, rc));
1192 }
1193 else if (RT_FAILURE(rc))
1194 rc = VERR_TRY_AGAIN;
1195 }
1196 return rc;
1197}
1198
1199
1200/**
1201 * Handles VMMDevReq_RegisterPatchMemory.
1202 *
1203 * @returns VBox status code that the guest should see.
1204 * @param pThis The VMMDev instance data.
1205 * @param pReqHdr The header of the request to handle.
1206 */
1207static int vmmdevReqHandler_RegisterPatchMemory(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
1208{
1209 VMMDevReqPatchMemory *pReq = (VMMDevReqPatchMemory *)pReqHdr;
1210 AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
1211
1212 return VMMR3RegisterPatchMemory(PDMDevHlpGetVM(pThis->pDevIns), pReq->pPatchMem, pReq->cbPatchMem);
1213}
1214
1215
1216/**
1217 * Handles VMMDevReq_DeregisterPatchMemory.
1218 *
1219 * @returns VBox status code that the guest should see.
1220 * @param pThis The VMMDev instance data.
1221 * @param pReqHdr The header of the request to handle.
1222 */
1223static int vmmdevReqHandler_DeregisterPatchMemory(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
1224{
1225 VMMDevReqPatchMemory *pReq = (VMMDevReqPatchMemory *)pReqHdr;
1226 AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
1227
1228 return VMMR3DeregisterPatchMemory(PDMDevHlpGetVM(pThis->pDevIns), pReq->pPatchMem, pReq->cbPatchMem);
1229}
1230
1231
1232/**
1233 * Handles VMMDevReq_SetPowerStatus.
1234 *
1235 * @returns VBox status code that the guest should see.
1236 * @param pThis The VMMDev instance data.
1237 * @param pReqHdr The header of the request to handle.
1238 */
1239static int vmmdevReqHandler_SetPowerStatus(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
1240{
1241 VMMDevPowerStateRequest *pReq = (VMMDevPowerStateRequest *)pReqHdr;
1242 AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
1243
1244 switch (pReq->powerState)
1245 {
1246 case VMMDevPowerState_Pause:
1247 {
1248 LogRel(("VMMDev: Guest requests the VM to be suspended (paused)\n"));
1249 return PDMDevHlpVMSuspend(pThis->pDevIns);
1250 }
1251
1252 case VMMDevPowerState_PowerOff:
1253 {
1254 LogRel(("VMMDev: Guest requests the VM to be turned off\n"));
1255 return PDMDevHlpVMPowerOff(pThis->pDevIns);
1256 }
1257
1258 case VMMDevPowerState_SaveState:
1259 {
1260 if (true /*pThis->fAllowGuestToSaveState*/)
1261 {
1262 LogRel(("VMMDev: Guest requests the VM to be saved and powered off\n"));
1263 return PDMDevHlpVMSuspendSaveAndPowerOff(pThis->pDevIns);
1264 }
1265 LogRel(("VMMDev: Guest requests the VM to be saved and powered off, declined\n"));
1266 return VERR_ACCESS_DENIED;
1267 }
1268
1269 default:
1270 AssertMsgFailed(("VMMDev: Invalid power state request: %d\n", pReq->powerState));
1271 return VERR_INVALID_PARAMETER;
1272 }
1273}
1274
1275
1276/**
1277 * Handles VMMDevReq_GetDisplayChangeRequest
1278 *
1279 * @returns VBox status code that the guest should see.
1280 * @param pThis The VMMDev instance data.
1281 * @param pReqHdr The header of the request to handle.
1282 * @remarks Deprecated.
1283 */
1284static int vmmdevReqHandler_GetDisplayChangeRequest(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
1285{
1286 VMMDevDisplayChangeRequest *pReq = (VMMDevDisplayChangeRequest *)pReqHdr;
1287 AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
1288
1289/**
1290 * @todo It looks like a multi-monitor guest which only uses
1291 * @c VMMDevReq_GetDisplayChangeRequest (not the *2 version) will get
1292 * into a @c VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST event loop if it tries
1293 * to acknowlege host requests for additional monitors. Should the loop
1294 * which checks for those requests be removed?
1295 */
1296
1297 DISPLAYCHANGEREQUEST *pDispRequest = &pThis->displayChangeData.aRequests[0];
1298
1299 if (pReq->eventAck == VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST)
1300 {
1301 /* Current request has been read at least once. */
1302 pDispRequest->fPending = false;
1303
1304 /* Check if there are more pending requests. */
1305 for (unsigned i = 1; i < RT_ELEMENTS(pThis->displayChangeData.aRequests); i++)
1306 {
1307 if (pThis->displayChangeData.aRequests[i].fPending)
1308 {
1309 VMMDevNotifyGuest(pThis, VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST);
1310 break;
1311 }
1312 }
1313
1314 /* Remember which resolution the client has queried, subsequent reads
1315 * will return the same values. */
1316 pDispRequest->lastReadDisplayChangeRequest = pDispRequest->displayChangeRequest;
1317 pThis->displayChangeData.fGuestSentChangeEventAck = true;
1318 }
1319
1320 if (pThis->displayChangeData.fGuestSentChangeEventAck)
1321 {
1322 pReq->xres = pDispRequest->lastReadDisplayChangeRequest.xres;
1323 pReq->yres = pDispRequest->lastReadDisplayChangeRequest.yres;
1324 pReq->bpp = pDispRequest->lastReadDisplayChangeRequest.bpp;
1325 }
1326 else
1327 {
1328 /* This is not a response to a VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST, just
1329 * read the last valid video mode hint. This happens when the guest X server
1330 * determines the initial mode. */
1331 pReq->xres = pDispRequest->displayChangeRequest.xres;
1332 pReq->yres = pDispRequest->displayChangeRequest.yres;
1333 pReq->bpp = pDispRequest->displayChangeRequest.bpp;
1334 }
1335 Log(("VMMDev: returning display change request xres = %d, yres = %d, bpp = %d\n", pReq->xres, pReq->yres, pReq->bpp));
1336
1337 return VINF_SUCCESS;
1338}
1339
1340
1341/**
1342 * Handles VMMDevReq_GetDisplayChangeRequest2.
1343 *
1344 * @returns VBox status code that the guest should see.
1345 * @param pThis The VMMDev instance data.
1346 * @param pReqHdr The header of the request to handle.
1347 */
1348static int vmmdevReqHandler_GetDisplayChangeRequest2(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
1349{
1350 VMMDevDisplayChangeRequest2 *pReq = (VMMDevDisplayChangeRequest2 *)pReqHdr;
1351 AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
1352
1353 DISPLAYCHANGEREQUEST *pDispRequest = NULL;
1354
1355 if (pReq->eventAck == VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST)
1356 {
1357 /* Select a pending request to report. */
1358 unsigned i;
1359 for (i = 0; i < RT_ELEMENTS(pThis->displayChangeData.aRequests); i++)
1360 {
1361 if (pThis->displayChangeData.aRequests[i].fPending)
1362 {
1363 pDispRequest = &pThis->displayChangeData.aRequests[i];
1364 /* Remember which request should be reported. */
1365 pThis->displayChangeData.iCurrentMonitor = i;
1366 Log3(("VMMDev: will report pending request for %u\n", i));
1367 break;
1368 }
1369 }
1370
1371 /* Check if there are more pending requests. */
1372 i++;
1373 for (; i < RT_ELEMENTS(pThis->displayChangeData.aRequests); i++)
1374 {
1375 if (pThis->displayChangeData.aRequests[i].fPending)
1376 {
1377 VMMDevNotifyGuest(pThis, VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST);
1378 Log3(("VMMDev: another pending at %u\n", i));
1379 break;
1380 }
1381 }
1382
1383 if (pDispRequest)
1384 {
1385 /* Current request has been read at least once. */
1386 pDispRequest->fPending = false;
1387
1388 /* Remember which resolution the client has queried, subsequent reads
1389 * will return the same values. */
1390 pDispRequest->lastReadDisplayChangeRequest = pDispRequest->displayChangeRequest;
1391 pThis->displayChangeData.fGuestSentChangeEventAck = true;
1392 }
1393 else
1394 {
1395 Log3(("VMMDev: no pending request!!!\n"));
1396 }
1397 }
1398
1399 if (!pDispRequest)
1400 {
1401 Log3(("VMMDev: default to %d\n", pThis->displayChangeData.iCurrentMonitor));
1402 pDispRequest = &pThis->displayChangeData.aRequests[pThis->displayChangeData.iCurrentMonitor];
1403 }
1404
1405 if (pThis->displayChangeData.fGuestSentChangeEventAck)
1406 {
1407 pReq->xres = pDispRequest->lastReadDisplayChangeRequest.xres;
1408 pReq->yres = pDispRequest->lastReadDisplayChangeRequest.yres;
1409 pReq->bpp = pDispRequest->lastReadDisplayChangeRequest.bpp;
1410 pReq->display = pDispRequest->lastReadDisplayChangeRequest.display;
1411 }
1412 else
1413 {
1414 /* This is not a response to a VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST, just
1415 * read the last valid video mode hint. This happens when the guest X server
1416 * determines the initial video mode. */
1417 pReq->xres = pDispRequest->displayChangeRequest.xres;
1418 pReq->yres = pDispRequest->displayChangeRequest.yres;
1419 pReq->bpp = pDispRequest->displayChangeRequest.bpp;
1420 pReq->display = pDispRequest->displayChangeRequest.display;
1421 }
1422 Log(("VMMDev: returning display change request xres = %d, yres = %d, bpp = %d at %d\n",
1423 pReq->xres, pReq->yres, pReq->bpp, pReq->display));
1424
1425 return VINF_SUCCESS;
1426}
1427
1428
1429/**
1430 * Handles VMMDevReq_GetDisplayChangeRequestEx.
1431 *
1432 * @returns VBox status code that the guest should see.
1433 * @param pThis The VMMDev instance data.
1434 * @param pReqHdr The header of the request to handle.
1435 */
1436static int vmmdevReqHandler_GetDisplayChangeRequestEx(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
1437{
1438 VMMDevDisplayChangeRequestEx *pReq = (VMMDevDisplayChangeRequestEx *)pReqHdr;
1439 AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
1440
1441 DISPLAYCHANGEREQUEST *pDispRequest = NULL;
1442
1443 if (pReq->eventAck == VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST)
1444 {
1445 /* Select a pending request to report. */
1446 unsigned i;
1447 for (i = 0; i < RT_ELEMENTS(pThis->displayChangeData.aRequests); i++)
1448 {
1449 if (pThis->displayChangeData.aRequests[i].fPending)
1450 {
1451 pDispRequest = &pThis->displayChangeData.aRequests[i];
1452 /* Remember which request should be reported. */
1453 pThis->displayChangeData.iCurrentMonitor = i;
1454 Log3(("VMMDev: will report pending request for %d\n",
1455 i));
1456 break;
1457 }
1458 }
1459
1460 /* Check if there are more pending requests. */
1461 i++;
1462 for (; i < RT_ELEMENTS(pThis->displayChangeData.aRequests); i++)
1463 {
1464 if (pThis->displayChangeData.aRequests[i].fPending)
1465 {
1466 VMMDevNotifyGuest(pThis, VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST);
1467 Log3(("VMMDev: another pending at %d\n",
1468 i));
1469 break;
1470 }
1471 }
1472
1473 if (pDispRequest)
1474 {
1475 /* Current request has been read at least once. */
1476 pDispRequest->fPending = false;
1477
1478 /* Remember which resolution the client has queried, subsequent reads
1479 * will return the same values. */
1480 pDispRequest->lastReadDisplayChangeRequest = pDispRequest->displayChangeRequest;
1481 pThis->displayChangeData.fGuestSentChangeEventAck = true;
1482 }
1483 else
1484 {
1485 Log3(("VMMDev: no pending request!!!\n"));
1486 }
1487 }
1488
1489 if (!pDispRequest)
1490 {
1491 Log3(("VMMDev: default to %d\n",
1492 pThis->displayChangeData.iCurrentMonitor));
1493 pDispRequest = &pThis->displayChangeData.aRequests[pThis->displayChangeData.iCurrentMonitor];
1494 }
1495
1496 if (pThis->displayChangeData.fGuestSentChangeEventAck)
1497 {
1498 pReq->xres = pDispRequest->lastReadDisplayChangeRequest.xres;
1499 pReq->yres = pDispRequest->lastReadDisplayChangeRequest.yres;
1500 pReq->bpp = pDispRequest->lastReadDisplayChangeRequest.bpp;
1501 pReq->display = pDispRequest->lastReadDisplayChangeRequest.display;
1502 pReq->cxOrigin = pDispRequest->lastReadDisplayChangeRequest.xOrigin;
1503 pReq->cyOrigin = pDispRequest->lastReadDisplayChangeRequest.yOrigin;
1504 pReq->fEnabled = pDispRequest->lastReadDisplayChangeRequest.fEnabled;
1505 pReq->fChangeOrigin = pDispRequest->lastReadDisplayChangeRequest.fChangeOrigin;
1506 }
1507 else
1508 {
1509 /* This is not a response to a VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST, just
1510 * read the last valid video mode hint. This happens when the guest X server
1511 * determines the initial video mode. */
1512 pReq->xres = pDispRequest->displayChangeRequest.xres;
1513 pReq->yres = pDispRequest->displayChangeRequest.yres;
1514 pReq->bpp = pDispRequest->displayChangeRequest.bpp;
1515 pReq->display = pDispRequest->displayChangeRequest.display;
1516 pReq->cxOrigin = pDispRequest->displayChangeRequest.xOrigin;
1517 pReq->cyOrigin = pDispRequest->displayChangeRequest.yOrigin;
1518 pReq->fEnabled = pDispRequest->displayChangeRequest.fEnabled;
1519 pReq->fChangeOrigin = pDispRequest->displayChangeRequest.fChangeOrigin;
1520
1521 }
1522 Log(("VMMDevEx: returning display change request xres = %d, yres = %d, bpp = %d id %d xPos = %d, yPos = %d & Enabled=%d\n",
1523 pReq->xres, pReq->yres, pReq->bpp, pReq->display, pReq->cxOrigin, pReq->cyOrigin, pReq->fEnabled));
1524
1525 return VINF_SUCCESS;
1526}
1527
1528
1529/**
1530 * Handles VMMDevReq_VideoModeSupported.
1531 *
1532 * Query whether the given video mode is supported.
1533 *
1534 * @returns VBox status code that the guest should see.
1535 * @param pThis The VMMDev instance data.
1536 * @param pReqHdr The header of the request to handle.
1537 */
1538static int vmmdevReqHandler_VideoModeSupported(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
1539{
1540 VMMDevVideoModeSupportedRequest *pReq = (VMMDevVideoModeSupportedRequest *)pReqHdr;
1541 AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
1542
1543 /* forward the call */
1544 return pThis->pDrv->pfnVideoModeSupported(pThis->pDrv,
1545 0, /* primary screen. */
1546 pReq->width,
1547 pReq->height,
1548 pReq->bpp,
1549 &pReq->fSupported);
1550}
1551
1552
1553/**
1554 * Handles VMMDevReq_VideoModeSupported2.
1555 *
1556 * Query whether the given video mode is supported for a specific display
1557 *
1558 * @returns VBox status code that the guest should see.
1559 * @param pThis The VMMDev instance data.
1560 * @param pReqHdr The header of the request to handle.
1561 */
1562static int vmmdevReqHandler_VideoModeSupported2(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
1563{
1564 VMMDevVideoModeSupportedRequest2 *pReq = (VMMDevVideoModeSupportedRequest2 *)pReqHdr;
1565 AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
1566
1567 /* forward the call */
1568 return pThis->pDrv->pfnVideoModeSupported(pThis->pDrv,
1569 pReq->display,
1570 pReq->width,
1571 pReq->height,
1572 pReq->bpp,
1573 &pReq->fSupported);
1574}
1575
1576
1577
1578/**
1579 * Handles VMMDevReq_GetHeightReduction.
1580 *
1581 * @returns VBox status code that the guest should see.
1582 * @param pThis The VMMDev instance data.
1583 * @param pReqHdr The header of the request to handle.
1584 */
1585static int vmmdevReqHandler_GetHeightReduction(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
1586{
1587 VMMDevGetHeightReductionRequest *pReq = (VMMDevGetHeightReductionRequest *)pReqHdr;
1588 AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
1589
1590 /* forward the call */
1591 return pThis->pDrv->pfnGetHeightReduction(pThis->pDrv, &pReq->heightReduction);
1592}
1593
1594
1595/**
1596 * Handles VMMDevReq_AcknowledgeEvents.
1597 *
1598 * @returns VBox status code that the guest should see.
1599 * @param pThis The VMMDev instance data.
1600 * @param pReqHdr The header of the request to handle.
1601 */
1602static int vmmdevReqHandler_AcknowledgeEvents(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
1603{
1604 VMMDevEvents *pReq = (VMMDevEvents *)pReqHdr;
1605 AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
1606
1607 if (!VMMDEV_INTERFACE_VERSION_IS_1_03(pThis))
1608 {
1609 if (pThis->fNewGuestFilterMask)
1610 {
1611 pThis->fNewGuestFilterMask = false;
1612 pThis->u32GuestFilterMask = pThis->u32NewGuestFilterMask;
1613 }
1614
1615 pReq->events = pThis->u32HostEventFlags & pThis->u32GuestFilterMask;
1616
1617 pThis->u32HostEventFlags &= ~pThis->u32GuestFilterMask;
1618 pThis->pVMMDevRAMR3->V.V1_04.fHaveEvents = false;
1619 PDMDevHlpPCISetIrqNoWait(pThis->pDevIns, 0, 0);
1620 }
1621 else
1622 vmmdevSetIRQ_Legacy(pThis);
1623 return VINF_SUCCESS;
1624}
1625
1626
1627/**
1628 * Handles VMMDevReq_CtlGuestFilterMask.
1629 *
1630 * @returns VBox status code that the guest should see.
1631 * @param pThis The VMMDev instance data.
1632 * @param pReqHdr The header of the request to handle.
1633 */
1634static int vmmdevReqHandler_CtlGuestFilterMask(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
1635{
1636 VMMDevCtlGuestFilterMask *pReq = (VMMDevCtlGuestFilterMask *)pReqHdr;
1637 AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
1638
1639 LogRelFlow(("VMMDev: vmmdevReqHandler_CtlGuestFilterMask: OR mask: %#x, NOT mask: %#x\n", pReq->u32OrMask, pReq->u32NotMask));
1640
1641 /* HGCM event notification is enabled by the VMMDev device
1642 * automatically when any HGCM command is issued. The guest
1643 * cannot disable these notifications. */
1644 VMMDevCtlSetGuestFilterMask(pThis, pReq->u32OrMask, pReq->u32NotMask & ~VMMDEV_EVENT_HGCM);
1645 return VINF_SUCCESS;
1646}
1647
1648#ifdef VBOX_WITH_HGCM
1649
1650/**
1651 * Handles VMMDevReq_HGCMConnect.
1652 *
1653 * @returns VBox status code that the guest should see.
1654 * @param pThis The VMMDev instance data.
1655 * @param pReqHdr The header of the request to handle.
1656 * @param GCPhysReqHdr The guest physical address of the request header.
1657 */
1658static int vmmdevReqHandler_HGCMConnect(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr, RTGCPHYS GCPhysReqHdr)
1659{
1660 VMMDevHGCMConnect *pReq = (VMMDevHGCMConnect *)pReqHdr;
1661 AssertMsgReturn(pReq->header.header.size >= sizeof(*pReq), ("%u\n", pReq->header.header.size), VERR_INVALID_PARAMETER); /** @todo Not sure why this is >= ... */
1662
1663 if (pThis->pHGCMDrv)
1664 {
1665 Log(("VMMDevReq_HGCMConnect\n"));
1666 return vmmdevHGCMConnect(pThis, pReq, GCPhysReqHdr);
1667 }
1668
1669 Log(("VMMDevReq_HGCMConnect: HGCM Connector is NULL!\n"));
1670 return VERR_NOT_SUPPORTED;
1671}
1672
1673
1674/**
1675 * Handles VMMDevReq_HGCMDisconnect.
1676 *
1677 * @returns VBox status code that the guest should see.
1678 * @param pThis The VMMDev instance data.
1679 * @param pReqHdr The header of the request to handle.
1680 * @param GCPhysReqHdr The guest physical address of the request header.
1681 */
1682static int vmmdevReqHandler_HGCMDisconnect(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr, RTGCPHYS GCPhysReqHdr)
1683{
1684 VMMDevHGCMDisconnect *pReq = (VMMDevHGCMDisconnect *)pReqHdr;
1685 AssertMsgReturn(pReq->header.header.size >= sizeof(*pReq), ("%u\n", pReq->header.header.size), VERR_INVALID_PARAMETER); /** @todo Not sure why this >= ... */
1686
1687 if (pThis->pHGCMDrv)
1688 {
1689 Log(("VMMDevReq_VMMDevHGCMDisconnect\n"));
1690 return vmmdevHGCMDisconnect(pThis, pReq, GCPhysReqHdr);
1691 }
1692
1693 Log(("VMMDevReq_VMMDevHGCMDisconnect: HGCM Connector is NULL!\n"));
1694 return VERR_NOT_SUPPORTED;
1695}
1696
1697
1698/**
1699 * Handles VMMDevReq_HGCMCall.
1700 *
1701 * @returns VBox status code that the guest should see.
1702 * @param pThis The VMMDev instance data.
1703 * @param pReqHdr The header of the request to handle.
1704 * @param GCPhysReqHdr The guest physical address of the request header.
1705 */
1706static int vmmdevReqHandler_HGCMCall(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr, RTGCPHYS GCPhysReqHdr)
1707{
1708 VMMDevHGCMCall *pReq = (VMMDevHGCMCall *)pReqHdr;
1709 AssertMsgReturn(pReq->header.header.size >= sizeof(*pReq), ("%u\n", pReq->header.header.size), VERR_INVALID_PARAMETER);
1710
1711 if (pThis->pHGCMDrv)
1712 {
1713 Log2(("VMMDevReq_HGCMCall: sizeof(VMMDevHGCMRequest) = %04X\n", sizeof(VMMDevHGCMCall)));
1714 Log2(("%.*Rhxd\n", pReq->header.header.size, pReq));
1715
1716#ifdef VBOX_WITH_64_BITS_GUESTS
1717 bool f64Bits = (pReq->header.header.requestType == VMMDevReq_HGCMCall64);
1718#else
1719 bool f64Bits = false;
1720#endif /* VBOX_WITH_64_BITS_GUESTS */
1721
1722 return vmmdevHGCMCall(pThis, pReq, pReq->header.header.size, GCPhysReqHdr, f64Bits);
1723 }
1724
1725 Log(("VMMDevReq_HGCMCall: HGCM Connector is NULL!\n"));
1726 return VERR_NOT_SUPPORTED;
1727}
1728
1729/**
1730 * Handles VMMDevReq_HGCMCancel.
1731 *
1732 * @returns VBox status code that the guest should see.
1733 * @param pThis The VMMDev instance data.
1734 * @param pReqHdr The header of the request to handle.
1735 * @param GCPhysReqHdr The guest physical address of the request header.
1736 */
1737static int vmmdevReqHandler_HGCMCancel(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr, RTGCPHYS GCPhysReqHdr)
1738{
1739 VMMDevHGCMCancel *pReq = (VMMDevHGCMCancel *)pReqHdr;
1740 AssertMsgReturn(pReq->header.header.size >= sizeof(*pReq), ("%u\n", pReq->header.header.size), VERR_INVALID_PARAMETER); /** @todo Not sure why this >= ... */
1741
1742 if (pThis->pHGCMDrv)
1743 {
1744 Log(("VMMDevReq_VMMDevHGCMCancel\n"));
1745 return vmmdevHGCMCancel(pThis, pReq, GCPhysReqHdr);
1746 }
1747
1748 Log(("VMMDevReq_VMMDevHGCMCancel: HGCM Connector is NULL!\n"));
1749 return VERR_NOT_SUPPORTED;
1750}
1751
1752
1753/**
1754 * Handles VMMDevReq_HGCMCancel2.
1755 *
1756 * @returns VBox status code that the guest should see.
1757 * @param pThis The VMMDev instance data.
1758 * @param pReqHdr The header of the request to handle.
1759 */
1760static int vmmdevReqHandler_HGCMCancel2(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
1761{
1762 VMMDevHGCMCancel2 *pReq = (VMMDevHGCMCancel2 *)pReqHdr;
1763 AssertMsgReturn(pReq->header.size >= sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER); /** @todo Not sure why this >= ... */
1764
1765 if (pThis->pHGCMDrv)
1766 {
1767 Log(("VMMDevReq_HGCMCancel2\n"));
1768 return vmmdevHGCMCancel2(pThis, pReq->physReqToCancel);
1769 }
1770
1771 Log(("VMMDevReq_HGCMConnect2: HGCM Connector is NULL!\n"));
1772 return VERR_NOT_SUPPORTED;
1773}
1774
1775#endif /* VBOX_WITH_HGCM */
1776
1777
1778/**
1779 * Handles VMMDevReq_VideoAccelEnable.
1780 *
1781 * @returns VBox status code that the guest should see.
1782 * @param pThis The VMMDev instance data.
1783 * @param pReqHdr The header of the request to handle.
1784 */
1785static int vmmdevReqHandler_VideoAccelEnable(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
1786{
1787 VMMDevVideoAccelEnable *pReq = (VMMDevVideoAccelEnable *)pReqHdr;
1788 AssertMsgReturn(pReq->header.size >= sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER); /** @todo Not sure why this >= ... */
1789
1790 if (!pThis->pDrv)
1791 {
1792 Log(("VMMDevReq_VideoAccelEnable Connector is NULL!!\n"));
1793 return VERR_NOT_SUPPORTED;
1794 }
1795
1796 if (pReq->cbRingBuffer != VBVA_RING_BUFFER_SIZE)
1797 {
1798 /* The guest driver seems compiled with different headers. */
1799 LogRelMax(16,("VMMDevReq_VideoAccelEnable guest ring buffer size %#x, should be %#x!!\n", pReq->cbRingBuffer, VBVA_RING_BUFFER_SIZE));
1800 return VERR_INVALID_PARAMETER;
1801 }
1802
1803 /* The request is correct. */
1804 pReq->fu32Status |= VBVA_F_STATUS_ACCEPTED;
1805
1806 LogFlow(("VMMDevReq_VideoAccelEnable pReq->u32Enable = %d\n", pReq->u32Enable));
1807
1808 int rc = pReq->u32Enable
1809 ? pThis->pDrv->pfnVideoAccelEnable(pThis->pDrv, true, &pThis->pVMMDevRAMR3->vbvaMemory)
1810 : pThis->pDrv->pfnVideoAccelEnable(pThis->pDrv, false, NULL);
1811
1812 if ( pReq->u32Enable
1813 && RT_SUCCESS(rc))
1814 {
1815 pReq->fu32Status |= VBVA_F_STATUS_ENABLED;
1816
1817 /* Remember that guest successfully enabled acceleration.
1818 * We need to reestablish it on restoring the VM from saved state.
1819 */
1820 pThis->u32VideoAccelEnabled = 1;
1821 }
1822 else
1823 {
1824 /* The acceleration was not enabled. Remember that. */
1825 pThis->u32VideoAccelEnabled = 0;
1826 }
1827 return VINF_SUCCESS;
1828}
1829
1830
1831/**
1832 * Handles VMMDevReq_VideoAccelFlush.
1833 *
1834 * @returns VBox status code that the guest should see.
1835 * @param pThis The VMMDev instance data.
1836 * @param pReqHdr The header of the request to handle.
1837 */
1838static int vmmdevReqHandler_VideoAccelFlush(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
1839{
1840 VMMDevVideoAccelFlush *pReq = (VMMDevVideoAccelFlush *)pReqHdr;
1841 AssertMsgReturn(pReq->header.size >= sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER); /** @todo Not sure why this >= ... */
1842
1843 if (!pThis->pDrv)
1844 {
1845 Log(("VMMDevReq_VideoAccelFlush: Connector is NULL!!!\n"));
1846 return VERR_NOT_SUPPORTED;
1847 }
1848
1849 pThis->pDrv->pfnVideoAccelFlush(pThis->pDrv);
1850 return VINF_SUCCESS;
1851}
1852
1853
1854/**
1855 * Handles VMMDevReq_VideoSetVisibleRegion.
1856 *
1857 * @returns VBox status code that the guest should see.
1858 * @param pThis The VMMDev instance data.
1859 * @param pReqHdr The header of the request to handle.
1860 */
1861static int vmmdevReqHandler_VideoSetVisibleRegion(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
1862{
1863 VMMDevVideoSetVisibleRegion *pReq = (VMMDevVideoSetVisibleRegion *)pReqHdr;
1864 AssertMsgReturn(pReq->header.size + sizeof(RTRECT) >= sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
1865
1866 if (!pThis->pDrv)
1867 {
1868 Log(("VMMDevReq_VideoSetVisibleRegion: Connector is NULL!!!\n"));
1869 return VERR_NOT_SUPPORTED;
1870 }
1871
1872 if ( pReq->cRect > _1M /* restrict to sane range */
1873 || pReq->header.size != sizeof(VMMDevVideoSetVisibleRegion) + pReq->cRect * sizeof(RTRECT) - sizeof(RTRECT))
1874 {
1875 Log(("VMMDevReq_VideoSetVisibleRegion: cRects=%#x doesn't match size=%#x or is out of bounds\n",
1876 pReq->cRect, pReq->header.size));
1877 return VERR_INVALID_PARAMETER;
1878 }
1879
1880 Log(("VMMDevReq_VideoSetVisibleRegion %d rectangles\n", pReq->cRect));
1881 /* forward the call */
1882 return pThis->pDrv->pfnSetVisibleRegion(pThis->pDrv, pReq->cRect, &pReq->Rect);
1883}
1884
1885
1886/**
1887 * Handles VMMDevReq_GetSeamlessChangeRequest.
1888 *
1889 * @returns VBox status code that the guest should see.
1890 * @param pThis The VMMDev instance data.
1891 * @param pReqHdr The header of the request to handle.
1892 */
1893static int vmmdevReqHandler_GetSeamlessChangeRequest(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
1894{
1895 VMMDevSeamlessChangeRequest *pReq = (VMMDevSeamlessChangeRequest *)pReqHdr;
1896 AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
1897
1898 /* just pass on the information */
1899 Log(("VMMDev: returning seamless change request mode=%d\n", pThis->fSeamlessEnabled));
1900 if (pThis->fSeamlessEnabled)
1901 pReq->mode = VMMDev_Seamless_Visible_Region;
1902 else
1903 pReq->mode = VMMDev_Seamless_Disabled;
1904
1905 if (pReq->eventAck == VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST)
1906 {
1907 /* Remember which mode the client has queried. */
1908 pThis->fLastSeamlessEnabled = pThis->fSeamlessEnabled;
1909 }
1910
1911 return VINF_SUCCESS;
1912}
1913
1914
1915/**
1916 * Handles VMMDevReq_GetVRDPChangeRequest.
1917 *
1918 * @returns VBox status code that the guest should see.
1919 * @param pThis The VMMDev instance data.
1920 * @param pReqHdr The header of the request to handle.
1921 */
1922static int vmmdevReqHandler_GetVRDPChangeRequest(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
1923{
1924 VMMDevVRDPChangeRequest *pReq = (VMMDevVRDPChangeRequest *)pReqHdr;
1925 AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
1926
1927 /* just pass on the information */
1928 Log(("VMMDev: returning VRDP status %d level %d\n", pThis->fVRDPEnabled, pThis->uVRDPExperienceLevel));
1929
1930 pReq->u8VRDPActive = pThis->fVRDPEnabled;
1931 pReq->u32VRDPExperienceLevel = pThis->uVRDPExperienceLevel;
1932
1933 return VINF_SUCCESS;
1934}
1935
1936
1937/**
1938 * Handles VMMDevReq_GetMemBalloonChangeRequest.
1939 *
1940 * @returns VBox status code that the guest should see.
1941 * @param pThis The VMMDev instance data.
1942 * @param pReqHdr The header of the request to handle.
1943 */
1944static int vmmdevReqHandler_GetMemBalloonChangeRequest(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
1945{
1946 VMMDevGetMemBalloonChangeRequest *pReq = (VMMDevGetMemBalloonChangeRequest *)pReqHdr;
1947 AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
1948
1949 /* just pass on the information */
1950 Log(("VMMDev: returning memory balloon size =%d\n", pThis->cMbMemoryBalloon));
1951 pReq->cBalloonChunks = pThis->cMbMemoryBalloon;
1952 pReq->cPhysMemChunks = pThis->cbGuestRAM / (uint64_t)_1M;
1953
1954 if (pReq->eventAck == VMMDEV_EVENT_BALLOON_CHANGE_REQUEST)
1955 {
1956 /* Remember which mode the client has queried. */
1957 pThis->cMbMemoryBalloonLast = pThis->cMbMemoryBalloon;
1958 }
1959
1960 return VINF_SUCCESS;
1961}
1962
1963
1964/**
1965 * Handles VMMDevReq_ChangeMemBalloon.
1966 *
1967 * @returns VBox status code that the guest should see.
1968 * @param pThis The VMMDev instance data.
1969 * @param pReqHdr The header of the request to handle.
1970 */
1971static int vmmdevReqHandler_ChangeMemBalloon(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
1972{
1973 VMMDevChangeMemBalloon *pReq = (VMMDevChangeMemBalloon *)pReqHdr;
1974 AssertMsgReturn(pReq->header.size >= sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
1975 AssertMsgReturn(pReq->cPages == VMMDEV_MEMORY_BALLOON_CHUNK_PAGES, ("%u\n", pReq->cPages), VERR_INVALID_PARAMETER);
1976 AssertMsgReturn(pReq->header.size == (uint32_t)RT_OFFSETOF(VMMDevChangeMemBalloon, aPhysPage[pReq->cPages]),
1977 ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
1978
1979 Log(("VMMDevReq_ChangeMemBalloon\n"));
1980 int rc = PGMR3PhysChangeMemBalloon(PDMDevHlpGetVM(pThis->pDevIns), !!pReq->fInflate, pReq->cPages, pReq->aPhysPage);
1981 if (pReq->fInflate)
1982 STAM_REL_U32_INC(&pThis->StatMemBalloonChunks);
1983 else
1984 STAM_REL_U32_DEC(&pThis->StatMemBalloonChunks);
1985 return rc;
1986}
1987
1988
1989/**
1990 * Handles VMMDevReq_GetStatisticsChangeRequest.
1991 *
1992 * @returns VBox status code that the guest should see.
1993 * @param pThis The VMMDev instance data.
1994 * @param pReqHdr The header of the request to handle.
1995 */
1996static int vmmdevReqHandler_GetStatisticsChangeRequest(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
1997{
1998 VMMDevGetStatisticsChangeRequest *pReq = (VMMDevGetStatisticsChangeRequest *)pReqHdr;
1999 AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
2000
2001 Log(("VMMDevReq_GetStatisticsChangeRequest\n"));
2002 /* just pass on the information */
2003 Log(("VMMDev: returning statistics interval %d seconds\n", pThis->u32StatIntervalSize));
2004 pReq->u32StatInterval = pThis->u32StatIntervalSize;
2005
2006 if (pReq->eventAck == VMMDEV_EVENT_STATISTICS_INTERVAL_CHANGE_REQUEST)
2007 {
2008 /* Remember which mode the client has queried. */
2009 pThis->u32LastStatIntervalSize= pThis->u32StatIntervalSize;
2010 }
2011
2012 return VINF_SUCCESS;
2013}
2014
2015
2016/**
2017 * Handles VMMDevReq_ReportGuestStats.
2018 *
2019 * @returns VBox status code that the guest should see.
2020 * @param pThis The VMMDev instance data.
2021 * @param pReqHdr The header of the request to handle.
2022 */
2023static int vmmdevReqHandler_ReportGuestStats(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
2024{
2025 VMMDevReportGuestStats *pReq = (VMMDevReportGuestStats *)pReqHdr;
2026 AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
2027
2028 Log(("VMMDevReq_ReportGuestStats\n"));
2029#ifdef LOG_ENABLED
2030 VBoxGuestStatistics *pGuestStats = &pReq->guestStats;
2031
2032 Log(("Current statistics:\n"));
2033 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_CPU_LOAD_IDLE)
2034 Log(("CPU%u: CPU Load Idle %-3d%%\n", pGuestStats->u32CpuId, pGuestStats->u32CpuLoad_Idle));
2035
2036 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_CPU_LOAD_KERNEL)
2037 Log(("CPU%u: CPU Load Kernel %-3d%%\n", pGuestStats->u32CpuId, pGuestStats->u32CpuLoad_Kernel));
2038
2039 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_CPU_LOAD_USER)
2040 Log(("CPU%u: CPU Load User %-3d%%\n", pGuestStats->u32CpuId, pGuestStats->u32CpuLoad_User));
2041
2042 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_THREADS)
2043 Log(("CPU%u: Thread %d\n", pGuestStats->u32CpuId, pGuestStats->u32Threads));
2044
2045 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_PROCESSES)
2046 Log(("CPU%u: Processes %d\n", pGuestStats->u32CpuId, pGuestStats->u32Processes));
2047
2048 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_HANDLES)
2049 Log(("CPU%u: Handles %d\n", pGuestStats->u32CpuId, pGuestStats->u32Handles));
2050
2051 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_MEMORY_LOAD)
2052 Log(("CPU%u: Memory Load %d%%\n", pGuestStats->u32CpuId, pGuestStats->u32MemoryLoad));
2053
2054 /* Note that reported values are in pages; upper layers expect them in megabytes */
2055 Log(("CPU%u: Page size %-4d bytes\n", pGuestStats->u32CpuId, pGuestStats->u32PageSize));
2056 Assert(pGuestStats->u32PageSize == 4096);
2057
2058 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_PHYS_MEM_TOTAL)
2059 Log(("CPU%u: Total physical memory %-4d MB\n", pGuestStats->u32CpuId, (pGuestStats->u32PhysMemTotal + (_1M/_4K)-1) / (_1M/_4K)));
2060
2061 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_PHYS_MEM_AVAIL)
2062 Log(("CPU%u: Free physical memory %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32PhysMemAvail / (_1M/_4K)));
2063
2064 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_PHYS_MEM_BALLOON)
2065 Log(("CPU%u: Memory balloon size %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32PhysMemBalloon / (_1M/_4K)));
2066
2067 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_MEM_COMMIT_TOTAL)
2068 Log(("CPU%u: Committed memory %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32MemCommitTotal / (_1M/_4K)));
2069
2070 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_MEM_KERNEL_TOTAL)
2071 Log(("CPU%u: Total kernel memory %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32MemKernelTotal / (_1M/_4K)));
2072
2073 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_MEM_KERNEL_PAGED)
2074 Log(("CPU%u: Paged kernel memory %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32MemKernelPaged / (_1M/_4K)));
2075
2076 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_MEM_KERNEL_NONPAGED)
2077 Log(("CPU%u: Nonpaged kernel memory %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32MemKernelNonPaged / (_1M/_4K)));
2078
2079 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_MEM_SYSTEM_CACHE)
2080 Log(("CPU%u: System cache size %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32MemSystemCache / (_1M/_4K)));
2081
2082 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_PAGE_FILE_SIZE)
2083 Log(("CPU%u: Page file size %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32PageFileSize / (_1M/_4K)));
2084 Log(("Statistics end *******************\n"));
2085#endif /* LOG_ENABLED */
2086
2087 /* forward the call */
2088 return pThis->pDrv->pfnReportStatistics(pThis->pDrv, &pReq->guestStats);
2089}
2090
2091
2092/**
2093 * Handles VMMDevReq_QueryCredentials.
2094 *
2095 * @returns VBox status code that the guest should see.
2096 * @param pThis The VMMDev instance data.
2097 * @param pReqHdr The header of the request to handle.
2098 */
2099static int vmmdevReqHandler_QueryCredentials(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
2100{
2101 VMMDevCredentials *pReq = (VMMDevCredentials *)pReqHdr;
2102 AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
2103
2104 /* let's start by nulling out the data */
2105 memset(pReq->szUserName, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
2106 memset(pReq->szPassword, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
2107 memset(pReq->szDomain, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
2108
2109 /* should we return whether we got credentials for a logon? */
2110 if (pReq->u32Flags & VMMDEV_CREDENTIALS_QUERYPRESENCE)
2111 {
2112 if ( pThis->pCredentials->Logon.szUserName[0]
2113 || pThis->pCredentials->Logon.szPassword[0]
2114 || pThis->pCredentials->Logon.szDomain[0])
2115 pReq->u32Flags |= VMMDEV_CREDENTIALS_PRESENT;
2116 else
2117 pReq->u32Flags &= ~VMMDEV_CREDENTIALS_PRESENT;
2118 }
2119
2120 /* does the guest want to read logon credentials? */
2121 if (pReq->u32Flags & VMMDEV_CREDENTIALS_READ)
2122 {
2123 if (pThis->pCredentials->Logon.szUserName[0])
2124 strcpy(pReq->szUserName, pThis->pCredentials->Logon.szUserName);
2125 if (pThis->pCredentials->Logon.szPassword[0])
2126 strcpy(pReq->szPassword, pThis->pCredentials->Logon.szPassword);
2127 if (pThis->pCredentials->Logon.szDomain[0])
2128 strcpy(pReq->szDomain, pThis->pCredentials->Logon.szDomain);
2129 if (!pThis->pCredentials->Logon.fAllowInteractiveLogon)
2130 pReq->u32Flags |= VMMDEV_CREDENTIALS_NOLOCALLOGON;
2131 else
2132 pReq->u32Flags &= ~VMMDEV_CREDENTIALS_NOLOCALLOGON;
2133 }
2134
2135 if (!pThis->fKeepCredentials)
2136 {
2137 /* does the caller want us to destroy the logon credentials? */
2138 if (pReq->u32Flags & VMMDEV_CREDENTIALS_CLEAR)
2139 {
2140 memset(pThis->pCredentials->Logon.szUserName, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
2141 memset(pThis->pCredentials->Logon.szPassword, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
2142 memset(pThis->pCredentials->Logon.szDomain, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
2143 }
2144 }
2145
2146 /* does the guest want to read credentials for verification? */
2147 if (pReq->u32Flags & VMMDEV_CREDENTIALS_READJUDGE)
2148 {
2149 if (pThis->pCredentials->Judge.szUserName[0])
2150 strcpy(pReq->szUserName, pThis->pCredentials->Judge.szUserName);
2151 if (pThis->pCredentials->Judge.szPassword[0])
2152 strcpy(pReq->szPassword, pThis->pCredentials->Judge.szPassword);
2153 if (pThis->pCredentials->Judge.szDomain[0])
2154 strcpy(pReq->szDomain, pThis->pCredentials->Judge.szDomain);
2155 }
2156
2157 /* does the caller want us to destroy the judgement credentials? */
2158 if (pReq->u32Flags & VMMDEV_CREDENTIALS_CLEARJUDGE)
2159 {
2160 memset(pThis->pCredentials->Judge.szUserName, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
2161 memset(pThis->pCredentials->Judge.szPassword, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
2162 memset(pThis->pCredentials->Judge.szDomain, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
2163 }
2164
2165 return VINF_SUCCESS;
2166}
2167
2168
2169/**
2170 * Handles VMMDevReq_ReportCredentialsJudgement.
2171 *
2172 * @returns VBox status code that the guest should see.
2173 * @param pThis The VMMDev instance data.
2174 * @param pReqHdr The header of the request to handle.
2175 */
2176static int vmmdevReqHandler_ReportCredentialsJudgement(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
2177{
2178 VMMDevCredentials *pReq = (VMMDevCredentials *)pReqHdr;
2179 AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
2180
2181 /* what does the guest think about the credentials? (note: the order is important here!) */
2182 if (pReq->u32Flags & VMMDEV_CREDENTIALS_JUDGE_DENY)
2183 pThis->pDrv->pfnSetCredentialsJudgementResult(pThis->pDrv, VMMDEV_CREDENTIALS_JUDGE_DENY);
2184 else if (pReq->u32Flags & VMMDEV_CREDENTIALS_JUDGE_NOJUDGEMENT)
2185 pThis->pDrv->pfnSetCredentialsJudgementResult(pThis->pDrv, VMMDEV_CREDENTIALS_JUDGE_NOJUDGEMENT);
2186 else if (pReq->u32Flags & VMMDEV_CREDENTIALS_JUDGE_OK)
2187 pThis->pDrv->pfnSetCredentialsJudgementResult(pThis->pDrv, VMMDEV_CREDENTIALS_JUDGE_OK);
2188 else
2189 {
2190 Log(("VMMDevReq_ReportCredentialsJudgement: invalid flags: %d!!!\n", pReq->u32Flags));
2191 /** @todo why don't we return VERR_INVALID_PARAMETER to the guest? */
2192 }
2193
2194 return VINF_SUCCESS;
2195}
2196
2197
2198/**
2199 * Handles VMMDevReq_GetHostVersion.
2200 *
2201 * @returns VBox status code that the guest should see.
2202 * @param pThis The VMMDev instance data.
2203 * @param pReqHdr The header of the request to handle.
2204 * @since 3.1.0
2205 * @note The ring-0 VBoxGuestLib uses this to check whether
2206 * VMMDevHGCMParmType_PageList is supported.
2207 */
2208static int vmmdevReqHandler_GetHostVersion(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
2209{
2210 VMMDevReqHostVersion *pReq = (VMMDevReqHostVersion *)pReqHdr;
2211 AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
2212
2213 pReq->major = RTBldCfgVersionMajor();
2214 pReq->minor = RTBldCfgVersionMinor();
2215 pReq->build = RTBldCfgVersionBuild();
2216 pReq->revision = RTBldCfgRevision();
2217 pReq->features = VMMDEV_HVF_HGCM_PHYS_PAGE_LIST;
2218 return VINF_SUCCESS;
2219}
2220
2221
2222/**
2223 * Handles VMMDevReq_GetCpuHotPlugRequest.
2224 *
2225 * @returns VBox status code that the guest should see.
2226 * @param pThis The VMMDev instance data.
2227 * @param pReqHdr The header of the request to handle.
2228 */
2229static int vmmdevReqHandler_GetCpuHotPlugRequest(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
2230{
2231 VMMDevGetCpuHotPlugRequest *pReq = (VMMDevGetCpuHotPlugRequest *)pReqHdr;
2232 AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
2233
2234 pReq->enmEventType = pThis->enmCpuHotPlugEvent;
2235 pReq->idCpuCore = pThis->idCpuCore;
2236 pReq->idCpuPackage = pThis->idCpuPackage;
2237
2238 /* Clear the event */
2239 pThis->enmCpuHotPlugEvent = VMMDevCpuEventType_None;
2240 pThis->idCpuCore = UINT32_MAX;
2241 pThis->idCpuPackage = UINT32_MAX;
2242
2243 return VINF_SUCCESS;
2244}
2245
2246
2247/**
2248 * Handles VMMDevReq_SetCpuHotPlugStatus.
2249 *
2250 * @returns VBox status code that the guest should see.
2251 * @param pThis The VMMDev instance data.
2252 * @param pReqHdr The header of the request to handle.
2253 */
2254static int vmmdevReqHandler_SetCpuHotPlugStatus(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
2255{
2256 VMMDevCpuHotPlugStatusRequest *pReq = (VMMDevCpuHotPlugStatusRequest *)pReqHdr;
2257 AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
2258
2259 if (pReq->enmStatusType == VMMDevCpuStatusType_Disable)
2260 pThis->fCpuHotPlugEventsEnabled = false;
2261 else if (pReq->enmStatusType == VMMDevCpuStatusType_Enable)
2262 pThis->fCpuHotPlugEventsEnabled = true;
2263 else
2264 return VERR_INVALID_PARAMETER;
2265 return VINF_SUCCESS;
2266}
2267
2268
2269#ifdef DEBUG
2270/**
2271 * Handles VMMDevReq_LogString.
2272 *
2273 * @returns VBox status code that the guest should see.
2274 * @param pThis The VMMDev instance data.
2275 * @param pReqHdr The header of the request to handle.
2276 */
2277static int vmmdevReqHandler_LogString(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
2278{
2279 VMMDevReqLogString *pReq = (VMMDevReqLogString *)pReqHdr;
2280 AssertMsgReturn(pReq->header.size >= sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
2281 AssertMsgReturn(pReq->szString[pReq->header.size - RT_OFFSETOF(VMMDevReqLogString, szString) - 1] == '\0',
2282 ("not null terminated\n"), VERR_INVALID_PARAMETER);
2283
2284 LogIt(RTLOGGRPFLAGS_LEVEL_1, LOG_GROUP_DEV_VMM_BACKDOOR, ("DEBUG LOG: %s", pReq->szString));
2285 return VINF_SUCCESS;
2286}
2287#endif /* DEBUG */
2288
2289/**
2290 * Handles VMMDevReq_GetSessionId.
2291 *
2292 * Get a unique "session" ID for this VM, where the ID will be different after each
2293 * start, reset or restore of the VM. This can be used for restore detection
2294 * inside the guest.
2295 *
2296 * @returns VBox status code that the guest should see.
2297 * @param pThis The VMMDev instance data.
2298 * @param pReqHdr The header of the request to handle.
2299 */
2300static int vmmdevReqHandler_GetSessionId(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
2301{
2302 VMMDevReqSessionId *pReq = (VMMDevReqSessionId *)pReqHdr;
2303 AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
2304
2305 pReq->idSession = pThis->idSession;
2306 return VINF_SUCCESS;
2307}
2308
2309
2310#ifdef VBOX_WITH_PAGE_SHARING
2311
2312/**
2313 * Handles VMMDevReq_RegisterSharedModule.
2314 *
2315 * @returns VBox status code that the guest should see.
2316 * @param pThis The VMMDev instance data.
2317 * @param pReqHdr The header of the request to handle.
2318 */
2319static int vmmdevReqHandler_RegisterSharedModule(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
2320{
2321 /*
2322 * Basic input validation (more done by GMM).
2323 */
2324 VMMDevSharedModuleRegistrationRequest *pReq = (VMMDevSharedModuleRegistrationRequest *)pReqHdr;
2325 AssertMsgReturn(pReq->header.size >= sizeof(VMMDevSharedModuleRegistrationRequest),
2326 ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
2327 AssertMsgReturn(pReq->header.size == RT_UOFFSETOF(VMMDevSharedModuleRegistrationRequest, aRegions[pReq->cRegions]),
2328 ("%u cRegions=%u\n", pReq->header.size, pReq->cRegions), VERR_INVALID_PARAMETER);
2329
2330 AssertReturn(RTStrEnd(pReq->szName, sizeof(pReq->szName)), VERR_INVALID_PARAMETER);
2331 AssertReturn(RTStrEnd(pReq->szVersion, sizeof(pReq->szVersion)), VERR_INVALID_PARAMETER);
2332 int rc = RTStrValidateEncoding(pReq->szName);
2333 AssertRCReturn(rc, rc);
2334 rc = RTStrValidateEncoding(pReq->szVersion);
2335 AssertRCReturn(rc, rc);
2336
2337 /*
2338 * Forward the request to the VMM.
2339 */
2340 return PGMR3SharedModuleRegister(PDMDevHlpGetVM(pThis->pDevIns), pReq->enmGuestOS, pReq->szName, pReq->szVersion,
2341 pReq->GCBaseAddr, pReq->cbModule, pReq->cRegions, pReq->aRegions);
2342}
2343
2344/**
2345 * Handles VMMDevReq_UnregisterSharedModule.
2346 *
2347 * @returns VBox status code that the guest should see.
2348 * @param pThis The VMMDev instance data.
2349 * @param pReqHdr The header of the request to handle.
2350 */
2351static int vmmdevReqHandler_UnregisterSharedModule(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
2352{
2353 /*
2354 * Basic input validation.
2355 */
2356 VMMDevSharedModuleUnregistrationRequest *pReq = (VMMDevSharedModuleUnregistrationRequest *)pReqHdr;
2357 AssertMsgReturn(pReq->header.size == sizeof(VMMDevSharedModuleUnregistrationRequest),
2358 ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
2359
2360 AssertReturn(RTStrEnd(pReq->szName, sizeof(pReq->szName)), VERR_INVALID_PARAMETER);
2361 AssertReturn(RTStrEnd(pReq->szVersion, sizeof(pReq->szVersion)), VERR_INVALID_PARAMETER);
2362 int rc = RTStrValidateEncoding(pReq->szName);
2363 AssertRCReturn(rc, rc);
2364 rc = RTStrValidateEncoding(pReq->szVersion);
2365 AssertRCReturn(rc, rc);
2366
2367 /*
2368 * Forward the request to the VMM.
2369 */
2370 return PGMR3SharedModuleUnregister(PDMDevHlpGetVM(pThis->pDevIns), pReq->szName, pReq->szVersion,
2371 pReq->GCBaseAddr, pReq->cbModule);
2372}
2373
2374/**
2375 * Handles VMMDevReq_CheckSharedModules.
2376 *
2377 * @returns VBox status code that the guest should see.
2378 * @param pThis The VMMDev instance data.
2379 * @param pReqHdr The header of the request to handle.
2380 */
2381static int vmmdevReqHandler_CheckSharedModules(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
2382{
2383 VMMDevSharedModuleCheckRequest *pReq = (VMMDevSharedModuleCheckRequest *)pReqHdr;
2384 AssertMsgReturn(pReq->header.size == sizeof(VMMDevSharedModuleCheckRequest),
2385 ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
2386 return PGMR3SharedModuleCheckAll(PDMDevHlpGetVM(pThis->pDevIns));
2387}
2388
2389/**
2390 * Handles VMMDevReq_GetPageSharingStatus.
2391 *
2392 * @returns VBox status code that the guest should see.
2393 * @param pThis The VMMDev instance data.
2394 * @param pReqHdr The header of the request to handle.
2395 */
2396static int vmmdevReqHandler_GetPageSharingStatus(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
2397{
2398 VMMDevPageSharingStatusRequest *pReq = (VMMDevPageSharingStatusRequest *)pReqHdr;
2399 AssertMsgReturn(pReq->header.size == sizeof(VMMDevPageSharingStatusRequest),
2400 ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
2401
2402 pReq->fEnabled = false;
2403 int rc = pThis->pDrv->pfnIsPageFusionEnabled(pThis->pDrv, &pReq->fEnabled);
2404 if (RT_FAILURE(rc))
2405 pReq->fEnabled = false;
2406 return VINF_SUCCESS;
2407}
2408
2409
2410/**
2411 * Handles VMMDevReq_DebugIsPageShared.
2412 *
2413 * @returns VBox status code that the guest should see.
2414 * @param pThis The VMMDev instance data.
2415 * @param pReqHdr The header of the request to handle.
2416 */
2417static int vmmdevReqHandler_DebugIsPageShared(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
2418{
2419 VMMDevPageIsSharedRequest *pReq = (VMMDevPageIsSharedRequest *)pReqHdr;
2420 AssertMsgReturn(pReq->header.size == sizeof(VMMDevPageIsSharedRequest),
2421 ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
2422
2423# ifdef DEBUG
2424 return PGMR3SharedModuleGetPageState(PDMDevHlpGetVM(pThis->pDevIns), pReq->GCPtrPage, &pReq->fShared, &pReq->uPageFlags);
2425# else
2426 return VERR_NOT_IMPLEMENTED;
2427# endif
2428}
2429
2430#endif /* VBOX_WITH_PAGE_SHARING */
2431
2432
2433/**
2434 * Handles VMMDevReq_WriteCoreDumpe
2435 *
2436 * @returns VBox status code that the guest should see.
2437 * @param pThis The VMMDev instance data.
2438 * @param pReqHdr Pointer to the request header.
2439 */
2440static int vmmdevReqHandler_WriteCoreDump(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
2441{
2442 VMMDevReqWriteCoreDump *pReq = (VMMDevReqWriteCoreDump *)pReqHdr;
2443 AssertMsgReturn(pReq->header.size == sizeof(VMMDevReqWriteCoreDump), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
2444
2445 /*
2446 * Only available if explicitly enabled by the user.
2447 */
2448 if (!pThis->fGuestCoreDumpEnabled)
2449 return VERR_ACCESS_DENIED;
2450
2451 /*
2452 * User makes sure the directory exists before composing the path.
2453 */
2454 if (!RTDirExists(pThis->szGuestCoreDumpDir))
2455 return VERR_PATH_NOT_FOUND;
2456
2457 char szCorePath[RTPATH_MAX];
2458 RTStrCopy(szCorePath, sizeof(szCorePath), pThis->szGuestCoreDumpDir);
2459 RTPathAppend(szCorePath, sizeof(szCorePath), "VBox.core");
2460
2461 /*
2462 * Rotate existing cores based on number of additional cores to keep around.
2463 */
2464 if (pThis->cGuestCoreDumps > 0)
2465 for (int64_t i = pThis->cGuestCoreDumps - 1; i >= 0; i--)
2466 {
2467 char szFilePathOld[RTPATH_MAX];
2468 if (i == 0)
2469 RTStrCopy(szFilePathOld, sizeof(szFilePathOld), szCorePath);
2470 else
2471 RTStrPrintf(szFilePathOld, sizeof(szFilePathOld), "%s.%lld", szCorePath, i);
2472
2473 char szFilePathNew[RTPATH_MAX];
2474 RTStrPrintf(szFilePathNew, sizeof(szFilePathNew), "%s.%lld", szCorePath, i + 1);
2475 int vrc = RTFileMove(szFilePathOld, szFilePathNew, RTFILEMOVE_FLAGS_REPLACE);
2476 if (vrc == VERR_FILE_NOT_FOUND)
2477 RTFileDelete(szFilePathNew);
2478 }
2479
2480 /*
2481 * Write the core file.
2482 */
2483 PUVM pUVM = PDMDevHlpGetUVM(pThis->pDevIns);
2484 return DBGFR3CoreWrite(pUVM, szCorePath, true /*fReplaceFile*/);
2485}
2486
2487
2488/**
2489 * Dispatch the request to the appropriate handler function.
2490 *
2491 * @returns Port I/O handler exit code.
2492 * @param pThis The VMM device instance data.
2493 * @param pReqHdr The request header (cached in host memory).
2494 * @param GCPhysReqHdr The guest physical address of the request (for
2495 * HGCM).
2496 * @param pfDelayedUnlock Where to indicate whether the critical section exit
2497 * needs to be delayed till after the request has been
2498 * written back. This is a HGCM kludge, see critsect
2499 * work in hgcmCompletedWorker for more details.
2500 */
2501static int vmmdevReqDispatcher(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr, RTGCPHYS GCPhysReqHdr, bool *pfDelayedUnlock)
2502{
2503 int rcRet = VINF_SUCCESS;
2504 *pfDelayedUnlock = false;
2505
2506 switch (pReqHdr->requestType)
2507 {
2508 case VMMDevReq_ReportGuestInfo:
2509 pReqHdr->rc = vmmdevReqHandler_ReportGuestInfo(pThis, pReqHdr);
2510 break;
2511
2512 case VMMDevReq_ReportGuestInfo2:
2513 pReqHdr->rc = vmmdevReqHandler_ReportGuestInfo2(pThis, pReqHdr);
2514 break;
2515
2516 case VMMDevReq_ReportGuestStatus:
2517 pReqHdr->rc = vmmdevReqHandler_ReportGuestStatus(pThis, pReqHdr);
2518 break;
2519
2520 case VMMDevReq_ReportGuestUserState:
2521 pReqHdr->rc = vmmdevReqHandler_ReportGuestUserState(pThis, pReqHdr);
2522 break;
2523
2524 case VMMDevReq_ReportGuestCapabilities:
2525 pReqHdr->rc = vmmdevReqHandler_ReportGuestCapabilities(pThis, pReqHdr);
2526 break;
2527
2528 case VMMDevReq_SetGuestCapabilities:
2529 pReqHdr->rc = vmmdevReqHandler_SetGuestCapabilities(pThis, pReqHdr);
2530 break;
2531
2532 case VMMDevReq_WriteCoreDump:
2533 pReqHdr->rc = vmmdevReqHandler_WriteCoreDump(pThis, pReqHdr);
2534 break;
2535
2536 case VMMDevReq_GetMouseStatus:
2537 pReqHdr->rc = vmmdevReqHandler_GetMouseStatus(pThis, pReqHdr);
2538 break;
2539
2540 case VMMDevReq_SetMouseStatus:
2541 pReqHdr->rc = vmmdevReqHandler_SetMouseStatus(pThis, pReqHdr);
2542 break;
2543
2544 case VMMDevReq_SetPointerShape:
2545 pReqHdr->rc = vmmdevReqHandler_SetPointerShape(pThis, pReqHdr);
2546 break;
2547
2548 case VMMDevReq_GetHostTime:
2549 pReqHdr->rc = vmmdevReqHandler_GetHostTime(pThis, pReqHdr);
2550 break;
2551
2552 case VMMDevReq_GetHypervisorInfo:
2553 pReqHdr->rc = vmmdevReqHandler_GetHypervisorInfo(pThis, pReqHdr);
2554 break;
2555
2556 case VMMDevReq_SetHypervisorInfo:
2557 pReqHdr->rc = vmmdevReqHandler_SetHypervisorInfo(pThis, pReqHdr);
2558 break;
2559
2560 case VMMDevReq_RegisterPatchMemory:
2561 pReqHdr->rc = vmmdevReqHandler_RegisterPatchMemory(pThis, pReqHdr);
2562 break;
2563
2564 case VMMDevReq_DeregisterPatchMemory:
2565 pReqHdr->rc = vmmdevReqHandler_DeregisterPatchMemory(pThis, pReqHdr);
2566 break;
2567
2568 case VMMDevReq_SetPowerStatus:
2569 {
2570 int rc = pReqHdr->rc = vmmdevReqHandler_SetPowerStatus(pThis, pReqHdr);
2571 if (rc != VINF_SUCCESS && RT_SUCCESS(rc))
2572 rcRet = rc;
2573 break;
2574 }
2575
2576 case VMMDevReq_GetDisplayChangeRequest:
2577 pReqHdr->rc = vmmdevReqHandler_GetDisplayChangeRequest(pThis, pReqHdr);
2578 break;
2579
2580 case VMMDevReq_GetDisplayChangeRequest2:
2581 pReqHdr->rc = vmmdevReqHandler_GetDisplayChangeRequest2(pThis, pReqHdr);
2582 break;
2583
2584 case VMMDevReq_GetDisplayChangeRequestEx:
2585 pReqHdr->rc = vmmdevReqHandler_GetDisplayChangeRequestEx(pThis, pReqHdr);
2586 break;
2587
2588 case VMMDevReq_VideoModeSupported:
2589 pReqHdr->rc = vmmdevReqHandler_VideoModeSupported(pThis, pReqHdr);
2590 break;
2591
2592 case VMMDevReq_VideoModeSupported2:
2593 pReqHdr->rc = vmmdevReqHandler_VideoModeSupported2(pThis, pReqHdr);
2594 break;
2595
2596 case VMMDevReq_GetHeightReduction:
2597 pReqHdr->rc = vmmdevReqHandler_GetHeightReduction(pThis, pReqHdr);
2598 break;
2599
2600 case VMMDevReq_AcknowledgeEvents:
2601 pReqHdr->rc = vmmdevReqHandler_AcknowledgeEvents(pThis, pReqHdr);
2602 break;
2603
2604 case VMMDevReq_CtlGuestFilterMask:
2605 pReqHdr->rc = vmmdevReqHandler_CtlGuestFilterMask(pThis, pReqHdr);
2606 break;
2607
2608#ifdef VBOX_WITH_HGCM
2609 case VMMDevReq_HGCMConnect:
2610 pReqHdr->rc = vmmdevReqHandler_HGCMConnect(pThis, pReqHdr, GCPhysReqHdr);
2611 *pfDelayedUnlock = true;
2612 break;
2613
2614 case VMMDevReq_HGCMDisconnect:
2615 pReqHdr->rc = vmmdevReqHandler_HGCMDisconnect(pThis, pReqHdr, GCPhysReqHdr);
2616 *pfDelayedUnlock = true;
2617 break;
2618
2619# ifdef VBOX_WITH_64_BITS_GUESTS
2620 case VMMDevReq_HGCMCall32:
2621 case VMMDevReq_HGCMCall64:
2622# else
2623 case VMMDevReq_HGCMCall:
2624# endif /* VBOX_WITH_64_BITS_GUESTS */
2625 pReqHdr->rc = vmmdevReqHandler_HGCMCall(pThis, pReqHdr, GCPhysReqHdr);
2626 *pfDelayedUnlock = true;
2627 break;
2628
2629 case VMMDevReq_HGCMCancel:
2630 pReqHdr->rc = vmmdevReqHandler_HGCMCancel(pThis, pReqHdr, GCPhysReqHdr);
2631 *pfDelayedUnlock = true;
2632 break;
2633
2634 case VMMDevReq_HGCMCancel2:
2635 pReqHdr->rc = vmmdevReqHandler_HGCMCancel2(pThis, pReqHdr);
2636 break;
2637#endif /* VBOX_WITH_HGCM */
2638
2639 case VMMDevReq_VideoAccelEnable:
2640 pReqHdr->rc = vmmdevReqHandler_VideoAccelEnable(pThis, pReqHdr);
2641 break;
2642
2643 case VMMDevReq_VideoAccelFlush:
2644 pReqHdr->rc = vmmdevReqHandler_VideoAccelFlush(pThis, pReqHdr);
2645 break;
2646
2647 case VMMDevReq_VideoSetVisibleRegion:
2648 pReqHdr->rc = vmmdevReqHandler_VideoSetVisibleRegion(pThis, pReqHdr);
2649 break;
2650
2651 case VMMDevReq_GetSeamlessChangeRequest:
2652 pReqHdr->rc = vmmdevReqHandler_GetSeamlessChangeRequest(pThis, pReqHdr);
2653 break;
2654
2655 case VMMDevReq_GetVRDPChangeRequest:
2656 pReqHdr->rc = vmmdevReqHandler_GetVRDPChangeRequest(pThis, pReqHdr);
2657 break;
2658
2659 case VMMDevReq_GetMemBalloonChangeRequest:
2660 pReqHdr->rc = vmmdevReqHandler_GetMemBalloonChangeRequest(pThis, pReqHdr);
2661 break;
2662
2663 case VMMDevReq_ChangeMemBalloon:
2664 pReqHdr->rc = vmmdevReqHandler_ChangeMemBalloon(pThis, pReqHdr);
2665 break;
2666
2667 case VMMDevReq_GetStatisticsChangeRequest:
2668 pReqHdr->rc = vmmdevReqHandler_GetStatisticsChangeRequest(pThis, pReqHdr);
2669 break;
2670
2671 case VMMDevReq_ReportGuestStats:
2672 pReqHdr->rc = vmmdevReqHandler_ReportGuestStats(pThis, pReqHdr);
2673 break;
2674
2675 case VMMDevReq_QueryCredentials:
2676 pReqHdr->rc = vmmdevReqHandler_QueryCredentials(pThis, pReqHdr);
2677 break;
2678
2679 case VMMDevReq_ReportCredentialsJudgement:
2680 pReqHdr->rc = vmmdevReqHandler_ReportCredentialsJudgement(pThis, pReqHdr);
2681 break;
2682
2683 case VMMDevReq_GetHostVersion:
2684 pReqHdr->rc = vmmdevReqHandler_GetHostVersion(pThis, pReqHdr);
2685 break;
2686
2687 case VMMDevReq_GetCpuHotPlugRequest:
2688 pReqHdr->rc = vmmdevReqHandler_GetCpuHotPlugRequest(pThis, pReqHdr);
2689 break;
2690
2691 case VMMDevReq_SetCpuHotPlugStatus:
2692 pReqHdr->rc = vmmdevReqHandler_SetCpuHotPlugStatus(pThis, pReqHdr);
2693 break;
2694
2695#ifdef VBOX_WITH_PAGE_SHARING
2696 case VMMDevReq_RegisterSharedModule:
2697 pReqHdr->rc = vmmdevReqHandler_RegisterSharedModule(pThis, pReqHdr);
2698 break;
2699
2700 case VMMDevReq_UnregisterSharedModule:
2701 pReqHdr->rc = vmmdevReqHandler_UnregisterSharedModule(pThis, pReqHdr);
2702 break;
2703
2704 case VMMDevReq_CheckSharedModules:
2705 pReqHdr->rc = vmmdevReqHandler_CheckSharedModules(pThis, pReqHdr);
2706 break;
2707
2708 case VMMDevReq_GetPageSharingStatus:
2709 pReqHdr->rc = vmmdevReqHandler_GetPageSharingStatus(pThis, pReqHdr);
2710 break;
2711
2712 case VMMDevReq_DebugIsPageShared:
2713 pReqHdr->rc = vmmdevReqHandler_DebugIsPageShared(pThis, pReqHdr);
2714 break;
2715
2716#endif /* VBOX_WITH_PAGE_SHARING */
2717
2718#ifdef DEBUG
2719 case VMMDevReq_LogString:
2720 pReqHdr->rc = vmmdevReqHandler_LogString(pThis, pReqHdr);
2721 break;
2722#endif
2723
2724 case VMMDevReq_GetSessionId:
2725 pReqHdr->rc = vmmdevReqHandler_GetSessionId(pThis, pReqHdr);
2726 break;
2727
2728 /*
2729 * Guest wants to give up a timeslice.
2730 * Note! This was only ever used by experimental GAs!
2731 */
2732 /** @todo maybe we could just remove this? */
2733 case VMMDevReq_Idle:
2734 {
2735 /* just return to EMT telling it that we want to halt */
2736 rcRet = VINF_EM_HALT;
2737 break;
2738 }
2739
2740 case VMMDevReq_GuestHeartbeat:
2741 pReqHdr->rc = vmmDevReqHandler_GuestHeartbeat(pThis);
2742 break;
2743
2744 case VMMDevReq_HeartbeatConfigure:
2745 pReqHdr->rc = vmmDevReqHandler_HeartbeatConfigure(pThis, pReqHdr);
2746 break;
2747
2748 default:
2749 {
2750 pReqHdr->rc = VERR_NOT_IMPLEMENTED;
2751 Log(("VMMDev unknown request type %d\n", pReqHdr->requestType));
2752 break;
2753 }
2754 }
2755 return rcRet;
2756}
2757
2758
2759/**
2760 * @callback_method_impl{FNIOMIOPORTOUT, Port I/O Handler for the generic
2761 * request interface.}
2762 */
2763static DECLCALLBACK(int) vmmdevRequestHandler(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
2764{
2765 PVMMDEV pThis = (VMMDevState*)pvUser;
2766
2767 /*
2768 * The caller has passed the guest context physical address of the request
2769 * structure. We'll copy all of it into a heap buffer eventually, but we
2770 * will have to start off with the header.
2771 */
2772 VMMDevRequestHeader requestHeader;
2773 RT_ZERO(requestHeader);
2774 PDMDevHlpPhysRead(pDevIns, (RTGCPHYS)u32, &requestHeader, sizeof(requestHeader));
2775
2776 /* The structure size must be greater or equal to the header size. */
2777 if (requestHeader.size < sizeof(VMMDevRequestHeader))
2778 {
2779 Log(("VMMDev request header size too small! size = %d\n", requestHeader.size));
2780 return VINF_SUCCESS;
2781 }
2782
2783 /* Check the version of the header structure. */
2784 if (requestHeader.version != VMMDEV_REQUEST_HEADER_VERSION)
2785 {
2786 Log(("VMMDev: guest header version (0x%08X) differs from ours (0x%08X)\n", requestHeader.version, VMMDEV_REQUEST_HEADER_VERSION));
2787 return VINF_SUCCESS;
2788 }
2789
2790 Log2(("VMMDev request issued: %d\n", requestHeader.requestType));
2791
2792 int rcRet = VINF_SUCCESS;
2793 bool fDelayedUnlock = false;
2794 VMMDevRequestHeader *pRequestHeader = NULL;
2795
2796 /* Check that is doesn't exceed the max packet size. */
2797 if (requestHeader.size <= VMMDEV_MAX_VMMDEVREQ_SIZE)
2798 {
2799 /*
2800 * We require the GAs to report it's information before we let it have
2801 * access to all the functions. The VMMDevReq_ReportGuestInfo request
2802 * is the one which unlocks the access. Newer additions will first
2803 * issue VMMDevReq_ReportGuestInfo2, older ones doesn't know this one.
2804 * Two exceptions: VMMDevReq_GetHostVersion and VMMDevReq_WriteCoreDump.
2805 */
2806 if ( pThis->fu32AdditionsOk
2807 || requestHeader.requestType == VMMDevReq_ReportGuestInfo2
2808 || requestHeader.requestType == VMMDevReq_ReportGuestInfo
2809 || requestHeader.requestType == VMMDevReq_WriteCoreDump
2810 || requestHeader.requestType == VMMDevReq_GetHostVersion
2811 )
2812 {
2813 /*
2814 * The request looks fine. Allocate a heap block for it, read the
2815 * entire package from guest memory and feed it to the dispatcher.
2816 */
2817 pRequestHeader = (VMMDevRequestHeader *)RTMemAlloc(requestHeader.size);
2818 if (pRequestHeader)
2819 {
2820 memcpy(pRequestHeader, &requestHeader, sizeof(VMMDevRequestHeader));
2821 size_t cbLeft = requestHeader.size - sizeof(VMMDevRequestHeader);
2822 if (cbLeft)
2823 PDMDevHlpPhysRead(pDevIns,
2824 (RTGCPHYS)u32 + sizeof(VMMDevRequestHeader),
2825 (uint8_t *)pRequestHeader + sizeof(VMMDevRequestHeader),
2826 cbLeft);
2827
2828 PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
2829 rcRet = vmmdevReqDispatcher(pThis, pRequestHeader, u32, &fDelayedUnlock);
2830 if (!fDelayedUnlock)
2831 PDMCritSectLeave(&pThis->CritSect);
2832 }
2833 else
2834 {
2835 Log(("VMMDev: RTMemAlloc failed!\n"));
2836 requestHeader.rc = VERR_NO_MEMORY;
2837 }
2838 }
2839 else
2840 {
2841 LogRelMax(10, ("VMMDev: Guest has not yet reported to us -- refusing operation of request #%d\n",
2842 requestHeader.requestType));
2843 requestHeader.rc = VERR_NOT_SUPPORTED;
2844 }
2845 }
2846 else
2847 {
2848 LogRelMax(50, ("VMMDev: Request packet too big (%x), refusing operation\n", requestHeader.size));
2849 requestHeader.rc = VERR_NOT_SUPPORTED;
2850 }
2851
2852 /*
2853 * Write the result back to guest memory
2854 */
2855 if (pRequestHeader)
2856 {
2857 PDMDevHlpPhysWrite(pDevIns, u32, pRequestHeader, pRequestHeader->size);
2858 if (fDelayedUnlock)
2859 PDMCritSectLeave(&pThis->CritSect);
2860 RTMemFree(pRequestHeader);
2861 }
2862 else
2863 {
2864 /* early error case; write back header only */
2865 PDMDevHlpPhysWrite(pDevIns, u32, &requestHeader, sizeof(requestHeader));
2866 Assert(!fDelayedUnlock);
2867 }
2868
2869 return rcRet;
2870}
2871
2872
2873/* -=-=-=-=-=- PCI Device -=-=-=-=-=- */
2874
2875
2876/**
2877 * @callback_method_impl{FNPCIIOREGIONMAP,MMIO/MMIO2 regions}
2878 */
2879static DECLCALLBACK(int)
2880vmmdevIORAMRegionMap(PPCIDEVICE pPciDev, int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
2881{
2882 LogFlow(("vmmdevR3IORAMRegionMap: iRegion=%d GCPhysAddress=%RGp cb=%#x enmType=%d\n", iRegion, GCPhysAddress, cb, enmType));
2883 PVMMDEV pThis = RT_FROM_MEMBER(pPciDev, VMMDEV, PciDev);
2884 int rc;
2885
2886 if (iRegion == 1)
2887 {
2888 AssertReturn(enmType == PCI_ADDRESS_SPACE_MEM, VERR_INTERNAL_ERROR);
2889 Assert(pThis->pVMMDevRAMR3 != NULL);
2890 if (GCPhysAddress != NIL_RTGCPHYS)
2891 {
2892 /*
2893 * Map the MMIO2 memory.
2894 */
2895 pThis->GCPhysVMMDevRAM = GCPhysAddress;
2896 Assert(pThis->GCPhysVMMDevRAM == GCPhysAddress);
2897 rc = PDMDevHlpMMIO2Map(pPciDev->pDevIns, iRegion, GCPhysAddress);
2898 }
2899 else
2900 {
2901 /*
2902 * It is about to be unmapped, just clean up.
2903 */
2904 pThis->GCPhysVMMDevRAM = NIL_RTGCPHYS32;
2905 rc = VINF_SUCCESS;
2906 }
2907 }
2908 else if (iRegion == 2)
2909 {
2910 AssertReturn(enmType == PCI_ADDRESS_SPACE_MEM_PREFETCH, VERR_INTERNAL_ERROR);
2911 Assert(pThis->pVMMDevHeapR3 != NULL);
2912 if (GCPhysAddress != NIL_RTGCPHYS)
2913 {
2914 /*
2915 * Map the MMIO2 memory.
2916 */
2917 pThis->GCPhysVMMDevHeap = GCPhysAddress;
2918 Assert(pThis->GCPhysVMMDevHeap == GCPhysAddress);
2919 rc = PDMDevHlpMMIO2Map(pPciDev->pDevIns, iRegion, GCPhysAddress);
2920 if (RT_SUCCESS(rc))
2921 rc = PDMDevHlpRegisterVMMDevHeap(pPciDev->pDevIns, GCPhysAddress, pThis->pVMMDevHeapR3, VMMDEV_HEAP_SIZE);
2922 }
2923 else
2924 {
2925 /*
2926 * It is about to be unmapped, just clean up.
2927 */
2928 PDMDevHlpRegisterVMMDevHeap(pPciDev->pDevIns, NIL_RTGCPHYS, pThis->pVMMDevHeapR3, VMMDEV_HEAP_SIZE);
2929 pThis->GCPhysVMMDevHeap = NIL_RTGCPHYS32;
2930 rc = VINF_SUCCESS;
2931 }
2932 }
2933 else
2934 {
2935 AssertMsgFailed(("%d\n", iRegion));
2936 rc = VERR_INVALID_PARAMETER;
2937 }
2938
2939 return rc;
2940}
2941
2942
2943/**
2944 * @callback_method_impl{FNPCIIOREGIONMAP,I/O Port Region}
2945 */
2946static DECLCALLBACK(int)
2947vmmdevIOPortRegionMap(PPCIDEVICE pPciDev, int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
2948{
2949 PVMMDEV pThis = RT_FROM_MEMBER(pPciDev, VMMDEV, PciDev);
2950
2951 Assert(enmType == PCI_ADDRESS_SPACE_IO);
2952 Assert(iRegion == 0);
2953 AssertMsg(RT_ALIGN(GCPhysAddress, 8) == GCPhysAddress, ("Expected 8 byte alignment. GCPhysAddress=%#x\n", GCPhysAddress));
2954
2955 /*
2956 * Register our port IO handlers.
2957 */
2958 int rc = PDMDevHlpIOPortRegister(pPciDev->pDevIns, (RTIOPORT)GCPhysAddress + VMMDEV_PORT_OFF_REQUEST, 1,
2959 pThis, vmmdevRequestHandler, NULL, NULL, NULL, "VMMDev Request Handler");
2960 AssertRC(rc);
2961 return rc;
2962}
2963
2964
2965
2966/* -=-=-=-=-=- Backdoor Logging and Time Sync. -=-=-=-=-=- */
2967
2968/**
2969 * @callback_method_impl{FNIOMIOPORTOUT, Backdoor Logging.}
2970 */
2971static DECLCALLBACK(int) vmmdevBackdoorLog(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
2972{
2973 PVMMDEV pThis = PDMINS_2_DATA(pDevIns, VMMDevState *);
2974
2975 if (!pThis->fBackdoorLogDisabled && cb == 1 && Port == RTLOG_DEBUG_PORT)
2976 {
2977
2978 /* The raw version. */
2979 switch (u32)
2980 {
2981 case '\r': LogIt(RTLOGGRPFLAGS_LEVEL_2, LOG_GROUP_DEV_VMM_BACKDOOR, ("vmmdev: <return>\n")); break;
2982 case '\n': LogIt(RTLOGGRPFLAGS_LEVEL_2, LOG_GROUP_DEV_VMM_BACKDOOR, ("vmmdev: <newline>\n")); break;
2983 case '\t': LogIt(RTLOGGRPFLAGS_LEVEL_2, LOG_GROUP_DEV_VMM_BACKDOOR, ("vmmdev: <tab>\n")); break;
2984 default: LogIt(RTLOGGRPFLAGS_LEVEL_2, LOG_GROUP_DEV_VMM_BACKDOOR, ("vmmdev: %c (%02x)\n", u32, u32)); break;
2985 }
2986
2987 /* The readable, buffered version. */
2988 if (u32 == '\n' || u32 == '\r')
2989 {
2990 pThis->szMsg[pThis->iMsg] = '\0';
2991 if (pThis->iMsg)
2992 LogRelIt(RTLOGGRPFLAGS_LEVEL_1, LOG_GROUP_DEV_VMM_BACKDOOR, ("VMMDev: Guest Log: %s\n", pThis->szMsg));
2993 pThis->iMsg = 0;
2994 }
2995 else
2996 {
2997 if (pThis->iMsg >= sizeof(pThis->szMsg)-1)
2998 {
2999 pThis->szMsg[pThis->iMsg] = '\0';
3000 LogRelIt(RTLOGGRPFLAGS_LEVEL_1, LOG_GROUP_DEV_VMM_BACKDOOR, ("VMMDev: Guest Log: %s\n", pThis->szMsg));
3001 pThis->iMsg = 0;
3002 }
3003 pThis->szMsg[pThis->iMsg] = (char )u32;
3004 pThis->szMsg[++pThis->iMsg] = '\0';
3005 }
3006 }
3007 return VINF_SUCCESS;
3008}
3009
3010#ifdef VMMDEV_WITH_ALT_TIMESYNC
3011
3012/**
3013 * @callback_method_impl{FNIOMIOPORTOUT, Alternative time synchronization.}
3014 */
3015static DECLCALLBACK(int) vmmdevAltTimeSyncWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
3016{
3017 PVMMDEV pThis = PDMINS_2_DATA(pDevIns, VMMDevState *);
3018 if (cb == 4)
3019 {
3020 /* Selects high (0) or low (1) DWORD. The high has to be read first. */
3021 switch (u32)
3022 {
3023 case 0:
3024 pThis->fTimesyncBackdoorLo = false;
3025 break;
3026 case 1:
3027 pThis->fTimesyncBackdoorLo = true;
3028 break;
3029 default:
3030 Log(("vmmdevAltTimeSyncWrite: Invalid access cb=%#x u32=%#x\n", cb, u32));
3031 break;
3032 }
3033 }
3034 else
3035 Log(("vmmdevAltTimeSyncWrite: Invalid access cb=%#x u32=%#x\n", cb, u32));
3036 return VINF_SUCCESS;
3037}
3038
3039/**
3040 * @callback_method_impl{FNIOMIOPORTOUT, Alternative time synchronization.}
3041 */
3042static DECLCALLBACK(int) vmmdevAltTimeSyncRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
3043{
3044 PVMMDEV pThis = PDMINS_2_DATA(pDevIns, VMMDevState *);
3045 int rc;
3046 if (cb == 4)
3047 {
3048 if (pThis->fTimesyncBackdoorLo)
3049 *pu32 = (uint32_t)pThis->hostTime;
3050 else
3051 {
3052 /* Reading the high dword gets and saves the current time. */
3053 RTTIMESPEC Now;
3054 pThis->hostTime = RTTimeSpecGetMilli(PDMDevHlpTMUtcNow(pDevIns, &Now));
3055 *pu32 = (uint32_t)(pThis->hostTime >> 32);
3056 }
3057 rc = VINF_SUCCESS;
3058 }
3059 else
3060 {
3061 Log(("vmmdevAltTimeSyncRead: Invalid access cb=%#x\n", cb));
3062 rc = VERR_IOM_IOPORT_UNUSED;
3063 }
3064 return rc;
3065}
3066
3067#endif /* VMMDEV_WITH_ALT_TIMESYNC */
3068
3069
3070/* -=-=-=-=-=- IBase -=-=-=-=-=- */
3071
3072/**
3073 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
3074 */
3075static DECLCALLBACK(void *) vmmdevPortQueryInterface(PPDMIBASE pInterface, const char *pszIID)
3076{
3077 PVMMDEV pThis = RT_FROM_MEMBER(pInterface, VMMDEV, IBase);
3078
3079 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
3080 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIVMMDEVPORT, &pThis->IPort);
3081#ifdef VBOX_WITH_HGCM
3082 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHGCMPORT, &pThis->IHGCMPort);
3083#endif
3084 /* Currently only for shared folders. */
3085 PDMIBASE_RETURN_INTERFACE(pszIID, PDMILEDPORTS, &pThis->SharedFolders.ILeds);
3086 return NULL;
3087}
3088
3089
3090/* -=-=-=-=-=- ILeds -=-=-=-=-=- */
3091
3092/**
3093 * Gets the pointer to the status LED of a unit.
3094 *
3095 * @returns VBox status code.
3096 * @param pInterface Pointer to the interface structure containing the called function pointer.
3097 * @param iLUN The unit which status LED we desire.
3098 * @param ppLed Where to store the LED pointer.
3099 */
3100static DECLCALLBACK(int) vmmdevQueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)
3101{
3102 PVMMDEV pThis = RT_FROM_MEMBER(pInterface, VMMDEV, SharedFolders.ILeds);
3103 if (iLUN == 0) /* LUN 0 is shared folders */
3104 {
3105 *ppLed = &pThis->SharedFolders.Led;
3106 return VINF_SUCCESS;
3107 }
3108 return VERR_PDM_LUN_NOT_FOUND;
3109}
3110
3111
3112/* -=-=-=-=-=- PDMIVMMDEVPORT (VMMDEV::IPort) -=-=-=-=-=- */
3113
3114/**
3115 * @interface_method_impl{PDMIVMMDEVPORT,pfnQueryAbsoluteMouse}
3116 */
3117static DECLCALLBACK(int) vmmdevIPort_QueryAbsoluteMouse(PPDMIVMMDEVPORT pInterface, int32_t *pxAbs, int32_t *pyAbs)
3118{
3119 PVMMDEV pThis = RT_FROM_MEMBER(pInterface, VMMDEV, IPort);
3120
3121 /** @todo at the first sign of trouble in this area, just enter the critsect.
3122 * As indicated by the comment below, the atomic reads serves no real purpose
3123 * here since we can assume cache coherency protocoles and int32_t alignment
3124 * rules making sure we won't see a halfwritten value. */
3125 if (pxAbs)
3126 *pxAbs = ASMAtomicReadS32(&pThis->mouseXAbs); /* why the atomic read? */
3127 if (pyAbs)
3128 *pyAbs = ASMAtomicReadS32(&pThis->mouseYAbs);
3129
3130 return VINF_SUCCESS;
3131}
3132
3133/**
3134 * @interface_method_impl{PDMIVMMDEVPORT,pfnSetAbsoluteMouse}
3135 */
3136static DECLCALLBACK(int) vmmdevIPort_SetAbsoluteMouse(PPDMIVMMDEVPORT pInterface, int32_t xAbs, int32_t yAbs)
3137{
3138 PVMMDEV pThis = RT_FROM_MEMBER(pInterface, VMMDEV, IPort);
3139 PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
3140
3141 if ( pThis->mouseXAbs != xAbs
3142 || pThis->mouseYAbs != yAbs)
3143 {
3144 Log2(("vmmdevIPort_SetAbsoluteMouse : settings absolute position to x = %d, y = %d\n", xAbs, yAbs));
3145 pThis->mouseXAbs = xAbs;
3146 pThis->mouseYAbs = yAbs;
3147 VMMDevNotifyGuest(pThis, VMMDEV_EVENT_MOUSE_POSITION_CHANGED);
3148 }
3149
3150 PDMCritSectLeave(&pThis->CritSect);
3151 return VINF_SUCCESS;
3152}
3153
3154/**
3155 * @interface_method_impl{PDMIVMMDEVPORT,pfnQueryMouseCapabilities}
3156 */
3157static DECLCALLBACK(int) vmmdevIPort_QueryMouseCapabilities(PPDMIVMMDEVPORT pInterface, uint32_t *pfCapabilities)
3158{
3159 PVMMDEV pThis = RT_FROM_MEMBER(pInterface, VMMDEV, IPort);
3160 AssertPtrReturn(pfCapabilities, VERR_INVALID_PARAMETER);
3161
3162 *pfCapabilities = pThis->mouseCapabilities;
3163 return VINF_SUCCESS;
3164}
3165
3166/**
3167 * @interface_method_impl{PDMIVMMDEVPORT,pfnUpdateMouseCapabilities}
3168 */
3169static DECLCALLBACK(int)
3170vmmdevIPort_UpdateMouseCapabilities(PPDMIVMMDEVPORT pInterface, uint32_t fCapsAdded, uint32_t fCapsRemoved)
3171{
3172 PVMMDEV pThis = RT_FROM_MEMBER(pInterface, VMMDEV, IPort);
3173 PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
3174
3175 uint32_t fOldCaps = pThis->mouseCapabilities;
3176 pThis->mouseCapabilities &= ~(fCapsRemoved & VMMDEV_MOUSE_HOST_MASK);
3177 pThis->mouseCapabilities |= (fCapsAdded & VMMDEV_MOUSE_HOST_MASK)
3178 | VMMDEV_MOUSE_HOST_RECHECKS_NEEDS_HOST_CURSOR;
3179 bool fNotify = fOldCaps != pThis->mouseCapabilities;
3180
3181 LogRelFlow(("VMMDev: vmmdevIPort_UpdateMouseCapabilities: fCapsAdded=0x%x, fCapsRemoved=0x%x, fNotify=%RTbool\n", fCapsAdded,
3182 fCapsRemoved, fNotify));
3183
3184 if (fNotify)
3185 VMMDevNotifyGuest(pThis, VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED);
3186
3187 PDMCritSectLeave(&pThis->CritSect);
3188 return VINF_SUCCESS;
3189}
3190
3191/**
3192 * @interface_method_impl{PDMIVMMDEVPORT,pfnRequestDisplayChange}
3193 */
3194static DECLCALLBACK(int)
3195vmmdevIPort_RequestDisplayChange(PPDMIVMMDEVPORT pInterface, uint32_t cx, uint32_t cy, uint32_t cBits, uint32_t idxDisplay,
3196 int32_t xOrigin, int32_t yOrigin, bool fEnabled, bool fChangeOrigin)
3197{
3198 PVMMDEV pThis = RT_FROM_MEMBER(pInterface, VMMDEV, IPort);
3199
3200 if (idxDisplay >= RT_ELEMENTS(pThis->displayChangeData.aRequests))
3201 return VERR_INVALID_PARAMETER;
3202
3203 PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
3204
3205 DISPLAYCHANGEREQUEST *pRequest = &pThis->displayChangeData.aRequests[idxDisplay];
3206
3207 /* Verify that the new resolution is different and that guest does not yet know about it. */
3208 bool fSameResolution = (!cx || pRequest->lastReadDisplayChangeRequest.xres == cx)
3209 && (!cy || pRequest->lastReadDisplayChangeRequest.yres == cy)
3210 && (!cBits || pRequest->lastReadDisplayChangeRequest.bpp == cBits)
3211 && pRequest->lastReadDisplayChangeRequest.xOrigin == xOrigin
3212 && pRequest->lastReadDisplayChangeRequest.yOrigin == yOrigin
3213 && pRequest->lastReadDisplayChangeRequest.fEnabled == fEnabled
3214 && pRequest->lastReadDisplayChangeRequest.display == idxDisplay;
3215
3216 if (!cx && !cy && !cBits)
3217 {
3218 /* Special case of reset video mode. */
3219 fSameResolution = false;
3220 }
3221
3222 Log3(("vmmdevIPort_RequestDisplayChange: same=%d. new: cx=%d, cy=%d, cBits=%d, idxDisplay=%d.\
3223 old: cx=%d, cy=%d, cBits=%d, idxDisplay=%d. \n \
3224 ,OriginX = %d , OriginY=%d, Enabled=%d, ChangeOrigin=%d\n",
3225 fSameResolution, cx, cy, cBits, idxDisplay, pRequest->lastReadDisplayChangeRequest.xres,
3226 pRequest->lastReadDisplayChangeRequest.yres, pRequest->lastReadDisplayChangeRequest.bpp,
3227 pRequest->lastReadDisplayChangeRequest.display,
3228 xOrigin, yOrigin, fEnabled, fChangeOrigin));
3229
3230 /* we could validate the information here but hey, the guest can do that as well! */
3231 pRequest->displayChangeRequest.xres = cx;
3232 pRequest->displayChangeRequest.yres = cy;
3233 pRequest->displayChangeRequest.bpp = cBits;
3234 pRequest->displayChangeRequest.display = idxDisplay;
3235 pRequest->displayChangeRequest.xOrigin = xOrigin;
3236 pRequest->displayChangeRequest.yOrigin = yOrigin;
3237 pRequest->displayChangeRequest.fEnabled = fEnabled;
3238 pRequest->displayChangeRequest.fChangeOrigin = fChangeOrigin;
3239
3240 pRequest->fPending = !fSameResolution;
3241
3242 if (!fSameResolution)
3243 {
3244 LogRel(("VMMDev: SetVideoModeHint: Got a video mode hint (%dx%dx%d)@(%dx%d),(%d;%d) at %d\n",
3245 cx, cy, cBits, xOrigin, yOrigin, fEnabled, fChangeOrigin, idxDisplay));
3246
3247 /* IRQ so the guest knows what's going on */
3248 VMMDevNotifyGuest(pThis, VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST);
3249 }
3250
3251 PDMCritSectLeave(&pThis->CritSect);
3252 return VINF_SUCCESS;
3253}
3254
3255/**
3256 * @interface_method_impl{PDMIVMMDEVPORT,pfnRequestSeamlessChange}
3257 */
3258static DECLCALLBACK(int) vmmdevIPort_RequestSeamlessChange(PPDMIVMMDEVPORT pInterface, bool fEnabled)
3259{
3260 PVMMDEV pThis = RT_FROM_MEMBER(pInterface, VMMDEV, IPort);
3261 PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
3262
3263 /* Verify that the new resolution is different and that guest does not yet know about it. */
3264 bool fSameMode = (pThis->fLastSeamlessEnabled == fEnabled);
3265
3266 Log(("vmmdevIPort_RequestSeamlessChange: same=%d. new=%d\n", fSameMode, fEnabled));
3267
3268 if (!fSameMode)
3269 {
3270 /* we could validate the information here but hey, the guest can do that as well! */
3271 pThis->fSeamlessEnabled = fEnabled;
3272
3273 /* IRQ so the guest knows what's going on */
3274 VMMDevNotifyGuest(pThis, VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST);
3275 }
3276
3277 PDMCritSectLeave(&pThis->CritSect);
3278 return VINF_SUCCESS;
3279}
3280
3281/**
3282 * @interface_method_impl{PDMIVMMDEVPORT,pfnSetMemoryBalloon}
3283 */
3284static DECLCALLBACK(int) vmmdevIPort_SetMemoryBalloon(PPDMIVMMDEVPORT pInterface, uint32_t cMbBalloon)
3285{
3286 PVMMDEV pThis = RT_FROM_MEMBER(pInterface, VMMDEV, IPort);
3287 PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
3288
3289 /* Verify that the new resolution is different and that guest does not yet know about it. */
3290 Log(("vmmdevIPort_SetMemoryBalloon: old=%u new=%u\n", pThis->cMbMemoryBalloonLast, cMbBalloon));
3291 if (pThis->cMbMemoryBalloonLast != cMbBalloon)
3292 {
3293 /* we could validate the information here but hey, the guest can do that as well! */
3294 pThis->cMbMemoryBalloon = cMbBalloon;
3295
3296 /* IRQ so the guest knows what's going on */
3297 VMMDevNotifyGuest(pThis, VMMDEV_EVENT_BALLOON_CHANGE_REQUEST);
3298 }
3299
3300 PDMCritSectLeave(&pThis->CritSect);
3301 return VINF_SUCCESS;
3302}
3303
3304/**
3305 * @interface_method_impl{PDMIVMMDEVPORT,pfnVRDPChange}
3306 */
3307static DECLCALLBACK(int) vmmdevIPort_VRDPChange(PPDMIVMMDEVPORT pInterface, bool fVRDPEnabled, uint32_t uVRDPExperienceLevel)
3308{
3309 PVMMDEV pThis = RT_FROM_MEMBER(pInterface, VMMDEV, IPort);
3310 PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
3311
3312 bool fSame = (pThis->fVRDPEnabled == fVRDPEnabled);
3313
3314 Log(("vmmdevIPort_VRDPChange: old=%d. new=%d\n", pThis->fVRDPEnabled, fVRDPEnabled));
3315
3316 if (!fSame)
3317 {
3318 pThis->fVRDPEnabled = fVRDPEnabled;
3319 pThis->uVRDPExperienceLevel = uVRDPExperienceLevel;
3320
3321 VMMDevNotifyGuest(pThis, VMMDEV_EVENT_VRDP);
3322 }
3323
3324 PDMCritSectLeave(&pThis->CritSect);
3325 return VINF_SUCCESS;
3326}
3327
3328/**
3329 * @interface_method_impl{PDMIVMMDEVPORT,pfnSetStatisticsInterval}
3330 */
3331static DECLCALLBACK(int) vmmdevIPort_SetStatisticsInterval(PPDMIVMMDEVPORT pInterface, uint32_t cSecsStatInterval)
3332{
3333 PVMMDEV pThis = RT_FROM_MEMBER(pInterface, VMMDEV, IPort);
3334 PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
3335
3336 /* Verify that the new resolution is different and that guest does not yet know about it. */
3337 bool fSame = (pThis->u32LastStatIntervalSize == cSecsStatInterval);
3338
3339 Log(("vmmdevIPort_SetStatisticsInterval: old=%d. new=%d\n", pThis->u32LastStatIntervalSize, cSecsStatInterval));
3340
3341 if (!fSame)
3342 {
3343 /* we could validate the information here but hey, the guest can do that as well! */
3344 pThis->u32StatIntervalSize = cSecsStatInterval;
3345
3346 /* IRQ so the guest knows what's going on */
3347 VMMDevNotifyGuest(pThis, VMMDEV_EVENT_STATISTICS_INTERVAL_CHANGE_REQUEST);
3348 }
3349
3350 PDMCritSectLeave(&pThis->CritSect);
3351 return VINF_SUCCESS;
3352}
3353
3354/**
3355 * @interface_method_impl{PDMIVMMDEVPORT,pfnSetCredentials}
3356 */
3357static DECLCALLBACK(int) vmmdevIPort_SetCredentials(PPDMIVMMDEVPORT pInterface, const char *pszUsername,
3358 const char *pszPassword, const char *pszDomain, uint32_t fFlags)
3359{
3360 PVMMDEV pThis = RT_FROM_MEMBER(pInterface, VMMDEV, IPort);
3361 AssertReturn(fFlags & (VMMDEV_SETCREDENTIALS_GUESTLOGON | VMMDEV_SETCREDENTIALS_JUDGE), VERR_INVALID_PARAMETER);
3362
3363 PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
3364
3365 /*
3366 * Logon mode
3367 */
3368 if (fFlags & VMMDEV_SETCREDENTIALS_GUESTLOGON)
3369 {
3370 /* memorize the data */
3371 strcpy(pThis->pCredentials->Logon.szUserName, pszUsername);
3372 strcpy(pThis->pCredentials->Logon.szPassword, pszPassword);
3373 strcpy(pThis->pCredentials->Logon.szDomain, pszDomain);
3374 pThis->pCredentials->Logon.fAllowInteractiveLogon = !(fFlags & VMMDEV_SETCREDENTIALS_NOLOCALLOGON);
3375 }
3376 /*
3377 * Credentials verification mode?
3378 */
3379 else
3380 {
3381 /* memorize the data */
3382 strcpy(pThis->pCredentials->Judge.szUserName, pszUsername);
3383 strcpy(pThis->pCredentials->Judge.szPassword, pszPassword);
3384 strcpy(pThis->pCredentials->Judge.szDomain, pszDomain);
3385
3386 VMMDevNotifyGuest(pThis, VMMDEV_EVENT_JUDGE_CREDENTIALS);
3387 }
3388
3389 PDMCritSectLeave(&pThis->CritSect);
3390 return VINF_SUCCESS;
3391}
3392
3393/**
3394 * @interface_method_impl{PDMIVMMDEVPORT,pfnVBVAChange}
3395 *
3396 * Notification from the Display. Especially useful when acceleration is
3397 * disabled after a video mode change.
3398 */
3399static DECLCALLBACK(void) vmmdevIPort_VBVAChange(PPDMIVMMDEVPORT pInterface, bool fEnabled)
3400{
3401 PVMMDEV pThis = RT_FROM_MEMBER(pInterface, VMMDEV, IPort);
3402 Log(("vmmdevIPort_VBVAChange: fEnabled = %d\n", fEnabled));
3403
3404 /* Only used by saved state, which I guess is why we don't bother with locking here. */
3405 pThis->u32VideoAccelEnabled = fEnabled;
3406}
3407
3408/**
3409 * @interface_method_impl{PDMIVMMDEVPORT,pfnCpuHotUnplug}
3410 */
3411static DECLCALLBACK(int) vmmdevIPort_CpuHotUnplug(PPDMIVMMDEVPORT pInterface, uint32_t idCpuCore, uint32_t idCpuPackage)
3412{
3413 PVMMDEV pThis = RT_FROM_MEMBER(pInterface, VMMDEV, IPort);
3414 int rc = VINF_SUCCESS;
3415
3416 Log(("vmmdevIPort_CpuHotUnplug: idCpuCore=%u idCpuPackage=%u\n", idCpuCore, idCpuPackage));
3417
3418 PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
3419
3420 if (pThis->fCpuHotPlugEventsEnabled)
3421 {
3422 pThis->enmCpuHotPlugEvent = VMMDevCpuEventType_Unplug;
3423 pThis->idCpuCore = idCpuCore;
3424 pThis->idCpuPackage = idCpuPackage;
3425 VMMDevNotifyGuest(pThis, VMMDEV_EVENT_CPU_HOTPLUG);
3426 }
3427 else
3428 rc = VERR_VMMDEV_CPU_HOTPLUG_NOT_MONITORED_BY_GUEST;
3429
3430 PDMCritSectLeave(&pThis->CritSect);
3431 return rc;
3432}
3433
3434/**
3435 * @interface_method_impl{PDMIVMMDEVPORT,pfnCpuHotPlug}
3436 */
3437static DECLCALLBACK(int) vmmdevIPort_CpuHotPlug(PPDMIVMMDEVPORT pInterface, uint32_t idCpuCore, uint32_t idCpuPackage)
3438{
3439 PVMMDEV pThis = RT_FROM_MEMBER(pInterface, VMMDEV, IPort);
3440 int rc = VINF_SUCCESS;
3441
3442 Log(("vmmdevCpuPlug: idCpuCore=%u idCpuPackage=%u\n", idCpuCore, idCpuPackage));
3443
3444 PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
3445
3446 if (pThis->fCpuHotPlugEventsEnabled)
3447 {
3448 pThis->enmCpuHotPlugEvent = VMMDevCpuEventType_Plug;
3449 pThis->idCpuCore = idCpuCore;
3450 pThis->idCpuPackage = idCpuPackage;
3451 VMMDevNotifyGuest(pThis, VMMDEV_EVENT_CPU_HOTPLUG);
3452 }
3453 else
3454 rc = VERR_VMMDEV_CPU_HOTPLUG_NOT_MONITORED_BY_GUEST;
3455
3456 PDMCritSectLeave(&pThis->CritSect);
3457 return rc;
3458}
3459
3460
3461/* -=-=-=-=-=- Saved State -=-=-=-=-=- */
3462
3463/**
3464 * @callback_method_impl{FNSSMDEVLIVEEXEC}
3465 */
3466static DECLCALLBACK(int) vmmdevLiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
3467{
3468 PVMMDEV pThis = PDMINS_2_DATA(pDevIns, PVMMDEV);
3469
3470 SSMR3PutBool(pSSM, pThis->fGetHostTimeDisabled);
3471 SSMR3PutBool(pSSM, pThis->fBackdoorLogDisabled);
3472 SSMR3PutBool(pSSM, pThis->fKeepCredentials);
3473 SSMR3PutBool(pSSM, pThis->fHeapEnabled);
3474
3475 return VINF_SSM_DONT_CALL_AGAIN;
3476}
3477
3478
3479/**
3480 * @callback_method_impl{FNSSMDEVSAVEEXEC}
3481 */
3482static DECLCALLBACK(int) vmmdevSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
3483{
3484 PVMMDEV pThis = PDMINS_2_DATA(pDevIns, PVMMDEV);
3485 PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
3486
3487 vmmdevLiveExec(pDevIns, pSSM, SSM_PASS_FINAL);
3488
3489 SSMR3PutU32(pSSM, pThis->hypervisorSize);
3490 SSMR3PutU32(pSSM, pThis->mouseCapabilities);
3491 SSMR3PutS32(pSSM, pThis->mouseXAbs);
3492 SSMR3PutS32(pSSM, pThis->mouseYAbs);
3493
3494 SSMR3PutBool(pSSM, pThis->fNewGuestFilterMask);
3495 SSMR3PutU32(pSSM, pThis->u32NewGuestFilterMask);
3496 SSMR3PutU32(pSSM, pThis->u32GuestFilterMask);
3497 SSMR3PutU32(pSSM, pThis->u32HostEventFlags);
3498 /* The following is not strictly necessary as PGM restores MMIO2, keeping it for historical reasons. */
3499 SSMR3PutMem(pSSM, &pThis->pVMMDevRAMR3->V, sizeof(pThis->pVMMDevRAMR3->V));
3500
3501 SSMR3PutMem(pSSM, &pThis->guestInfo, sizeof(pThis->guestInfo));
3502 SSMR3PutU32(pSSM, pThis->fu32AdditionsOk);
3503 SSMR3PutU32(pSSM, pThis->u32VideoAccelEnabled);
3504 SSMR3PutBool(pSSM, pThis->displayChangeData.fGuestSentChangeEventAck);
3505
3506 SSMR3PutU32(pSSM, pThis->guestCaps);
3507
3508#ifdef VBOX_WITH_HGCM
3509 vmmdevHGCMSaveState(pThis, pSSM);
3510#endif /* VBOX_WITH_HGCM */
3511
3512 SSMR3PutU32(pSSM, pThis->fHostCursorRequested);
3513
3514 SSMR3PutU32(pSSM, pThis->guestInfo2.uFullVersion);
3515 SSMR3PutU32(pSSM, pThis->guestInfo2.uRevision);
3516 SSMR3PutU32(pSSM, pThis->guestInfo2.fFeatures);
3517 SSMR3PutStrZ(pSSM, pThis->guestInfo2.szName);
3518 SSMR3PutU32(pSSM, pThis->cFacilityStatuses);
3519 for (uint32_t i = 0; i < pThis->cFacilityStatuses; i++)
3520 {
3521 SSMR3PutU32(pSSM, pThis->aFacilityStatuses[i].enmFacility);
3522 SSMR3PutU32(pSSM, pThis->aFacilityStatuses[i].fFlags);
3523 SSMR3PutU16(pSSM, (uint16_t)pThis->aFacilityStatuses[i].enmStatus);
3524 SSMR3PutS64(pSSM, RTTimeSpecGetNano(&pThis->aFacilityStatuses[i].TimeSpecTS));
3525 }
3526
3527 /* Heartbeat: */
3528 SSMR3PutBool(pSSM, pThis->fHeartbeatActive);
3529 SSMR3PutBool(pSSM, pThis->fFlatlined);
3530 SSMR3PutU64(pSSM, pThis->nsLastHeartbeatTS);
3531 TMR3TimerSave(pThis->pFlatlinedTimer, pSSM);
3532
3533 PDMCritSectLeave(&pThis->CritSect);
3534 return VINF_SUCCESS;
3535}
3536
3537/**
3538 * @callback_method_impl{FNSSMDEVLOADEXEC}
3539 */
3540static DECLCALLBACK(int) vmmdevLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
3541{
3542 /** @todo The code load code is assuming we're always loaded into a freshly
3543 * constructed VM. */
3544 PVMMDEV pThis = PDMINS_2_DATA(pDevIns, PVMMDEV);
3545 int rc;
3546
3547 if ( uVersion > VMMDEV_SAVED_STATE_VERSION
3548 || uVersion < 6)
3549 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
3550
3551 /* config */
3552 if (uVersion > VMMDEV_SAVED_STATE_VERSION_VBOX_30)
3553 {
3554 bool f;
3555 rc = SSMR3GetBool(pSSM, &f); AssertRCReturn(rc, rc);
3556 if (pThis->fGetHostTimeDisabled != f)
3557 LogRel(("VMMDev: Config mismatch - fGetHostTimeDisabled: config=%RTbool saved=%RTbool\n", pThis->fGetHostTimeDisabled, f));
3558
3559 rc = SSMR3GetBool(pSSM, &f); AssertRCReturn(rc, rc);
3560 if (pThis->fBackdoorLogDisabled != f)
3561 LogRel(("VMMDev: Config mismatch - fBackdoorLogDisabled: config=%RTbool saved=%RTbool\n", pThis->fBackdoorLogDisabled, f));
3562
3563 rc = SSMR3GetBool(pSSM, &f); AssertRCReturn(rc, rc);
3564 if (pThis->fKeepCredentials != f)
3565 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - fKeepCredentials: config=%RTbool saved=%RTbool"),
3566 pThis->fKeepCredentials, f);
3567 rc = SSMR3GetBool(pSSM, &f); AssertRCReturn(rc, rc);
3568 if (pThis->fHeapEnabled != f)
3569 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - fHeapEnabled: config=%RTbool saved=%RTbool"),
3570 pThis->fHeapEnabled, f);
3571 }
3572
3573 if (uPass != SSM_PASS_FINAL)
3574 return VINF_SUCCESS;
3575
3576 /* state */
3577 SSMR3GetU32(pSSM, &pThis->hypervisorSize);
3578 SSMR3GetU32(pSSM, &pThis->mouseCapabilities);
3579 SSMR3GetS32(pSSM, &pThis->mouseXAbs);
3580 SSMR3GetS32(pSSM, &pThis->mouseYAbs);
3581
3582 SSMR3GetBool(pSSM, &pThis->fNewGuestFilterMask);
3583 SSMR3GetU32(pSSM, &pThis->u32NewGuestFilterMask);
3584 SSMR3GetU32(pSSM, &pThis->u32GuestFilterMask);
3585 SSMR3GetU32(pSSM, &pThis->u32HostEventFlags);
3586
3587 //SSMR3GetBool(pSSM, &pThis->pVMMDevRAMR3->fHaveEvents);
3588 // here be dragons (probably)
3589 SSMR3GetMem(pSSM, &pThis->pVMMDevRAMR3->V, sizeof (pThis->pVMMDevRAMR3->V));
3590
3591 SSMR3GetMem(pSSM, &pThis->guestInfo, sizeof (pThis->guestInfo));
3592 SSMR3GetU32(pSSM, &pThis->fu32AdditionsOk);
3593 SSMR3GetU32(pSSM, &pThis->u32VideoAccelEnabled);
3594 if (uVersion > 10)
3595 SSMR3GetBool(pSSM, &pThis->displayChangeData.fGuestSentChangeEventAck);
3596
3597 rc = SSMR3GetU32(pSSM, &pThis->guestCaps);
3598
3599 /* Attributes which were temporarily introduced in r30072 */
3600 if (uVersion == 7)
3601 {
3602 uint32_t temp;
3603 SSMR3GetU32(pSSM, &temp);
3604 rc = SSMR3GetU32(pSSM, &temp);
3605 }
3606 AssertRCReturn(rc, rc);
3607
3608#ifdef VBOX_WITH_HGCM
3609 rc = vmmdevHGCMLoadState(pThis, pSSM, uVersion);
3610 AssertRCReturn(rc, rc);
3611#endif /* VBOX_WITH_HGCM */
3612
3613 if (uVersion >= 10)
3614 rc = SSMR3GetU32(pSSM, &pThis->fHostCursorRequested);
3615 AssertRCReturn(rc, rc);
3616
3617 if (uVersion > VMMDEV_SAVED_STATE_VERSION_MISSING_GUEST_INFO_2)
3618 {
3619 SSMR3GetU32(pSSM, &pThis->guestInfo2.uFullVersion);
3620 SSMR3GetU32(pSSM, &pThis->guestInfo2.uRevision);
3621 SSMR3GetU32(pSSM, &pThis->guestInfo2.fFeatures);
3622 rc = SSMR3GetStrZ(pSSM, &pThis->guestInfo2.szName[0], sizeof(pThis->guestInfo2.szName));
3623 AssertRCReturn(rc, rc);
3624 }
3625
3626 if (uVersion > VMMDEV_SAVED_STATE_VERSION_MISSING_FACILITY_STATUSES)
3627 {
3628 uint32_t cFacilityStatuses;
3629 rc = SSMR3GetU32(pSSM, &cFacilityStatuses);
3630 AssertRCReturn(rc, rc);
3631
3632 for (uint32_t i = 0; i < cFacilityStatuses; i++)
3633 {
3634 uint32_t uFacility, fFlags;
3635 uint16_t uStatus;
3636 int64_t iTimeStampNano;
3637
3638 SSMR3GetU32(pSSM, &uFacility);
3639 SSMR3GetU32(pSSM, &fFlags);
3640 SSMR3GetU16(pSSM, &uStatus);
3641 rc = SSMR3GetS64(pSSM, &iTimeStampNano);
3642 AssertRCReturn(rc, rc);
3643
3644 PVMMDEVFACILITYSTATUSENTRY pEntry = vmmdevGetFacilityStatusEntry(pThis, (VBoxGuestFacilityType)uFacility);
3645 AssertLogRelMsgReturn(pEntry,
3646 ("VMMDev: Ran out of entries restoring the guest facility statuses. Saved state has %u.\n", cFacilityStatuses),
3647 VERR_OUT_OF_RESOURCES);
3648 pEntry->enmStatus = (VBoxGuestFacilityStatus)uStatus;
3649 pEntry->fFlags = fFlags;
3650 RTTimeSpecSetNano(&pEntry->TimeSpecTS, iTimeStampNano);
3651 }
3652 }
3653
3654 /*
3655 * Heartbeat.
3656 */
3657 if (uVersion >= VMMDEV_SAVED_STATE_VERSION_HEARTBEAT)
3658 {
3659 SSMR3GetBool(pSSM, (bool *)&pThis->fHeartbeatActive);
3660 SSMR3GetBool(pSSM, (bool *)&pThis->fFlatlined);
3661 SSMR3GetU64(pSSM, (uint64_t *)&pThis->nsLastHeartbeatTS);
3662 rc = TMR3TimerLoad(pThis->pFlatlinedTimer, pSSM);
3663 AssertRCReturn(rc, rc);
3664 if (pThis->fFlatlined)
3665 LogRel(("vmmdevLoadState: Guest has flatlined. Last heartbeat %'RU64 ns before state was saved.\n",
3666 TMTimerGetNano(pThis->pFlatlinedTimer) - pThis->nsLastHeartbeatTS));
3667 }
3668
3669 /*
3670 * On a resume, we send the capabilities changed message so
3671 * that listeners can sync their state again
3672 */
3673 Log(("vmmdevLoadState: capabilities changed (%x), informing connector\n", pThis->mouseCapabilities));
3674 if (pThis->pDrv)
3675 {
3676 pThis->pDrv->pfnUpdateMouseCapabilities(pThis->pDrv, pThis->mouseCapabilities);
3677 if (uVersion >= 10)
3678 pThis->pDrv->pfnUpdatePointerShape(pThis->pDrv,
3679 /*fVisible=*/!!pThis->fHostCursorRequested,
3680 /*fAlpha=*/false,
3681 /*xHot=*/0, /*yHot=*/0,
3682 /*cx=*/0, /*cy=*/0,
3683 /*pvShape=*/NULL);
3684 }
3685
3686 if (pThis->fu32AdditionsOk)
3687 {
3688 vmmdevLogGuestOsInfo(&pThis->guestInfo);
3689 if (pThis->pDrv)
3690 {
3691 if (pThis->guestInfo2.uFullVersion && pThis->pDrv->pfnUpdateGuestInfo2)
3692 pThis->pDrv->pfnUpdateGuestInfo2(pThis->pDrv, pThis->guestInfo2.uFullVersion, pThis->guestInfo2.szName,
3693 pThis->guestInfo2.uRevision, pThis->guestInfo2.fFeatures);
3694 if (pThis->pDrv->pfnUpdateGuestInfo)
3695 pThis->pDrv->pfnUpdateGuestInfo(pThis->pDrv, &pThis->guestInfo);
3696
3697 if (pThis->pDrv->pfnUpdateGuestStatus)
3698 {
3699 for (uint32_t i = 0; i < pThis->cFacilityStatuses; i++) /* ascending order! */
3700 if ( pThis->aFacilityStatuses[i].enmStatus != VBoxGuestFacilityStatus_Inactive
3701 || !pThis->aFacilityStatuses[i].fFixed)
3702 pThis->pDrv->pfnUpdateGuestStatus(pThis->pDrv,
3703 pThis->aFacilityStatuses[i].enmFacility,
3704 (uint16_t)pThis->aFacilityStatuses[i].enmStatus,
3705 pThis->aFacilityStatuses[i].fFlags,
3706 &pThis->aFacilityStatuses[i].TimeSpecTS);
3707 }
3708 }
3709 }
3710 if (pThis->pDrv && pThis->pDrv->pfnUpdateGuestCapabilities)
3711 pThis->pDrv->pfnUpdateGuestCapabilities(pThis->pDrv, pThis->guestCaps);
3712
3713 return VINF_SUCCESS;
3714}
3715
3716/**
3717 * Load state done callback. Notify guest of restore event.
3718 *
3719 * @returns VBox status code.
3720 * @param pDevIns The device instance.
3721 * @param pSSM The handle to the saved state.
3722 */
3723static DECLCALLBACK(int) vmmdevLoadStateDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
3724{
3725 PVMMDEV pThis = PDMINS_2_DATA(pDevIns, PVMMDEV);
3726
3727#ifdef VBOX_WITH_HGCM
3728 int rc = vmmdevHGCMLoadStateDone(pThis, pSSM);
3729 AssertLogRelRCReturn(rc, rc);
3730#endif /* VBOX_WITH_HGCM */
3731
3732 /* Reestablish the acceleration status. */
3733 if ( pThis->u32VideoAccelEnabled
3734 && pThis->pDrv)
3735 {
3736 pThis->pDrv->pfnVideoAccelEnable(pThis->pDrv, !!pThis->u32VideoAccelEnabled, &pThis->pVMMDevRAMR3->vbvaMemory);
3737 }
3738
3739 VMMDevNotifyGuest(pThis, VMMDEV_EVENT_RESTORED);
3740
3741 return VINF_SUCCESS;
3742}
3743
3744
3745/* -=-=-=-=- PDMDEVREG -=-=-=-=- */
3746
3747/**
3748 * (Re-)initializes the MMIO2 data.
3749 *
3750 * @param pThis Pointer to the VMMDev instance data.
3751 */
3752static void vmmdevInitRam(PVMMDEV pThis)
3753{
3754 memset(pThis->pVMMDevRAMR3, 0, sizeof(VMMDevMemory));
3755 pThis->pVMMDevRAMR3->u32Size = sizeof(VMMDevMemory);
3756 pThis->pVMMDevRAMR3->u32Version = VMMDEV_MEMORY_VERSION;
3757}
3758
3759
3760/**
3761 * @interface_method_impl{PDMDEVREG,pfnReset}
3762 */
3763static DECLCALLBACK(void) vmmdevReset(PPDMDEVINS pDevIns)
3764{
3765 PVMMDEV pThis = PDMINS_2_DATA(pDevIns, PVMMDEV);
3766 PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
3767
3768 /*
3769 * Reset the mouse integration feature bits
3770 */
3771 if (pThis->mouseCapabilities & VMMDEV_MOUSE_GUEST_MASK)
3772 {
3773 pThis->mouseCapabilities &= ~VMMDEV_MOUSE_GUEST_MASK;
3774 /* notify the connector */
3775 Log(("vmmdevReset: capabilities changed (%x), informing connector\n", pThis->mouseCapabilities));
3776 pThis->pDrv->pfnUpdateMouseCapabilities(pThis->pDrv, pThis->mouseCapabilities);
3777 }
3778 pThis->fHostCursorRequested = false;
3779
3780 pThis->hypervisorSize = 0;
3781
3782 /* re-initialize the VMMDev memory */
3783 if (pThis->pVMMDevRAMR3)
3784 vmmdevInitRam(pThis);
3785
3786 /* credentials have to go away (by default) */
3787 if (!pThis->fKeepCredentials)
3788 {
3789 memset(pThis->pCredentials->Logon.szUserName, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
3790 memset(pThis->pCredentials->Logon.szPassword, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
3791 memset(pThis->pCredentials->Logon.szDomain, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
3792 }
3793 memset(pThis->pCredentials->Judge.szUserName, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
3794 memset(pThis->pCredentials->Judge.szPassword, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
3795 memset(pThis->pCredentials->Judge.szDomain, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
3796
3797 /* Reset means that additions will report again. */
3798 const bool fVersionChanged = pThis->fu32AdditionsOk
3799 || pThis->guestInfo.interfaceVersion
3800 || pThis->guestInfo.osType != VBOXOSTYPE_Unknown;
3801 if (fVersionChanged)
3802 Log(("vmmdevReset: fu32AdditionsOk=%d additionsVersion=%x osType=%#x\n",
3803 pThis->fu32AdditionsOk, pThis->guestInfo.interfaceVersion, pThis->guestInfo.osType));
3804 pThis->fu32AdditionsOk = false;
3805 memset (&pThis->guestInfo, 0, sizeof (pThis->guestInfo));
3806 RT_ZERO(pThis->guestInfo2);
3807 const bool fCapsChanged = pThis->guestCaps != 0; /* Report transition to 0. */
3808 pThis->guestCaps = 0;
3809
3810 /* Clear facilities. No need to tell Main as it will get a
3811 pfnUpdateGuestInfo callback. */
3812 RTTIMESPEC TimeStampNow;
3813 RTTimeNow(&TimeStampNow);
3814 uint32_t iFacility = pThis->cFacilityStatuses;
3815 while (iFacility-- > 0)
3816 {
3817 pThis->aFacilityStatuses[iFacility].enmStatus = VBoxGuestFacilityStatus_Inactive;
3818 pThis->aFacilityStatuses[iFacility].TimeSpecTS = TimeStampNow;
3819 }
3820
3821 /* clear pending display change request. */
3822 for (unsigned i = 0; i < RT_ELEMENTS(pThis->displayChangeData.aRequests); i++)
3823 {
3824 DISPLAYCHANGEREQUEST *pRequest = &pThis->displayChangeData.aRequests[i];
3825 memset (&pRequest->lastReadDisplayChangeRequest, 0, sizeof (pRequest->lastReadDisplayChangeRequest));
3826 }
3827 pThis->displayChangeData.iCurrentMonitor = 0;
3828 pThis->displayChangeData.fGuestSentChangeEventAck = false;
3829
3830 /* disable seamless mode */
3831 pThis->fLastSeamlessEnabled = false;
3832
3833 /* disabled memory ballooning */
3834 pThis->cMbMemoryBalloonLast = 0;
3835
3836 /* disabled statistics updating */
3837 pThis->u32LastStatIntervalSize = 0;
3838
3839#ifdef VBOX_WITH_HGCM
3840 /* Clear the "HGCM event enabled" flag so the event can be automatically reenabled. */
3841 pThis->u32HGCMEnabled = 0;
3842#endif
3843
3844 /*
3845 * Deactive heartbeat.
3846 */
3847 if (pThis->fHeartbeatActive)
3848 {
3849 TMTimerStop(pThis->pFlatlinedTimer);
3850 pThis->fFlatlined = false;
3851 pThis->fHeartbeatActive = true;
3852 }
3853
3854 /*
3855 * Clear the event variables.
3856 *
3857 * XXX By design we should NOT clear pThis->u32HostEventFlags because it is designed
3858 * that way so host events do not depend on guest resets. However, the pending
3859 * event flags actually _were_ cleared since ages so we mask out events from
3860 * clearing which we really need to survive the reset. See xtracker 5767.
3861 */
3862 pThis->u32HostEventFlags &= VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST;
3863 pThis->u32GuestFilterMask = 0;
3864 pThis->u32NewGuestFilterMask = 0;
3865 pThis->fNewGuestFilterMask = 0;
3866
3867 /*
3868 * Call the update functions as required.
3869 */
3870 if (fVersionChanged && pThis->pDrv && pThis->pDrv->pfnUpdateGuestInfo)
3871 pThis->pDrv->pfnUpdateGuestInfo(pThis->pDrv, &pThis->guestInfo);
3872 if (fCapsChanged && pThis->pDrv && pThis->pDrv->pfnUpdateGuestCapabilities)
3873 pThis->pDrv->pfnUpdateGuestCapabilities(pThis->pDrv, pThis->guestCaps);
3874
3875 /*
3876 * Generate a unique session id for this VM; it will be changed for each start, reset or restore.
3877 * This can be used for restore detection inside the guest.
3878 */
3879 pThis->idSession = ASMReadTSC();
3880
3881 PDMCritSectLeave(&pThis->CritSect);
3882}
3883
3884
3885/**
3886 * @interface_method_impl{PDMDEVREG,pfnRelocate}
3887 */
3888static DECLCALLBACK(void) vmmdevRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
3889{
3890 NOREF(pDevIns);
3891 NOREF(offDelta);
3892}
3893
3894
3895/**
3896 * @interface_method_impl{PDMDEVREG,pfnDestruct}
3897 */
3898static DECLCALLBACK(int) vmmdevDestruct(PPDMDEVINS pDevIns)
3899{
3900 PVMMDEV pThis = PDMINS_2_DATA(pDevIns, PVMMDEV);
3901 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
3902
3903 /*
3904 * Wipe and free the credentials.
3905 */
3906 if (pThis->pCredentials)
3907 {
3908 RTMemWipeThoroughly(pThis->pCredentials, sizeof(*pThis->pCredentials), 10);
3909 RTMemFree(pThis->pCredentials);
3910 pThis->pCredentials = NULL;
3911 }
3912
3913#ifdef VBOX_WITH_HGCM
3914 vmmdevHGCMDestroy(pThis);
3915#endif
3916
3917#ifndef VBOX_WITHOUT_TESTING_FEATURES
3918 /*
3919 * Clean up the testing device.
3920 */
3921 vmmdevTestingTerminate(pDevIns);
3922#endif
3923
3924 return VINF_SUCCESS;
3925}
3926
3927
3928/**
3929 * @interface_method_impl{PDMDEVREG,pfnConstruct}
3930 */
3931static DECLCALLBACK(int) vmmdevConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
3932{
3933 PVMMDEV pThis = PDMINS_2_DATA(pDevIns, PVMMDEV);
3934 int rc;
3935
3936 Assert(iInstance == 0);
3937 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
3938
3939 /*
3940 * Initialize data (most of it anyway).
3941 */
3942 /* Save PDM device instance data for future reference. */
3943 pThis->pDevIns = pDevIns;
3944
3945 /* PCI vendor, just a free bogus value */
3946 PCIDevSetVendorId(&pThis->PciDev, 0x80ee);
3947 /* device ID */
3948 PCIDevSetDeviceId(&pThis->PciDev, 0xcafe);
3949 /* class sub code (other type of system peripheral) */
3950 PCIDevSetClassSub(&pThis->PciDev, 0x80);
3951 /* class base code (base system peripheral) */
3952 PCIDevSetClassBase(&pThis->PciDev, 0x08);
3953 /* header type */
3954 PCIDevSetHeaderType(&pThis->PciDev, 0x00);
3955 /* interrupt on pin 0 */
3956 PCIDevSetInterruptPin(&pThis->PciDev, 0x01);
3957
3958 RTTIMESPEC TimeStampNow;
3959 RTTimeNow(&TimeStampNow);
3960 vmmdevAllocFacilityStatusEntry(pThis, VBoxGuestFacilityType_VBoxGuestDriver, true /*fFixed*/, &TimeStampNow);
3961 vmmdevAllocFacilityStatusEntry(pThis, VBoxGuestFacilityType_VBoxService, true /*fFixed*/, &TimeStampNow);
3962 vmmdevAllocFacilityStatusEntry(pThis, VBoxGuestFacilityType_VBoxTrayClient, true /*fFixed*/, &TimeStampNow);
3963 vmmdevAllocFacilityStatusEntry(pThis, VBoxGuestFacilityType_Seamless, true /*fFixed*/, &TimeStampNow);
3964 vmmdevAllocFacilityStatusEntry(pThis, VBoxGuestFacilityType_Graphics, true /*fFixed*/, &TimeStampNow);
3965 Assert(pThis->cFacilityStatuses == 5);
3966
3967 /*
3968 * Interfaces
3969 */
3970 /* IBase */
3971 pThis->IBase.pfnQueryInterface = vmmdevPortQueryInterface;
3972
3973 /* VMMDev port */
3974 pThis->IPort.pfnQueryAbsoluteMouse = vmmdevIPort_QueryAbsoluteMouse;
3975 pThis->IPort.pfnSetAbsoluteMouse = vmmdevIPort_SetAbsoluteMouse ;
3976 pThis->IPort.pfnQueryMouseCapabilities = vmmdevIPort_QueryMouseCapabilities;
3977 pThis->IPort.pfnUpdateMouseCapabilities = vmmdevIPort_UpdateMouseCapabilities;
3978 pThis->IPort.pfnRequestDisplayChange = vmmdevIPort_RequestDisplayChange;
3979 pThis->IPort.pfnSetCredentials = vmmdevIPort_SetCredentials;
3980 pThis->IPort.pfnVBVAChange = vmmdevIPort_VBVAChange;
3981 pThis->IPort.pfnRequestSeamlessChange = vmmdevIPort_RequestSeamlessChange;
3982 pThis->IPort.pfnSetMemoryBalloon = vmmdevIPort_SetMemoryBalloon;
3983 pThis->IPort.pfnSetStatisticsInterval = vmmdevIPort_SetStatisticsInterval;
3984 pThis->IPort.pfnVRDPChange = vmmdevIPort_VRDPChange;
3985 pThis->IPort.pfnCpuHotUnplug = vmmdevIPort_CpuHotUnplug;
3986 pThis->IPort.pfnCpuHotPlug = vmmdevIPort_CpuHotPlug;
3987
3988 /* Shared folder LED */
3989 pThis->SharedFolders.Led.u32Magic = PDMLED_MAGIC;
3990 pThis->SharedFolders.ILeds.pfnQueryStatusLed = vmmdevQueryStatusLed;
3991
3992#ifdef VBOX_WITH_HGCM
3993 /* HGCM port */
3994 pThis->IHGCMPort.pfnCompleted = hgcmCompleted;
3995#endif
3996
3997 pThis->pCredentials = (VMMDEVCREDS *)RTMemAllocZ(sizeof(*pThis->pCredentials));
3998 if (!pThis->pCredentials)
3999 return VERR_NO_MEMORY;
4000
4001
4002 /*
4003 * Validate and read the configuration.
4004 */
4005 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns,
4006 "GetHostTimeDisabled|"
4007 "BackdoorLogDisabled|"
4008 "KeepCredentials|"
4009 "HeapEnabled|"
4010 "RamSize|"
4011 "RZEnabled|"
4012 "GuestCoreDumpEnabled|"
4013 "GuestCoreDumpDir|"
4014 "GuestCoreDumpCount|"
4015 "HeartbeatInterval|"
4016 "HeartbeatTimeout|"
4017 "TestingEnabled|"
4018 "TestingMMIO|"
4019 "TestintXmlOutputFile"
4020 ,
4021 "");
4022
4023 rc = CFGMR3QueryU64(pCfg, "RamSize", &pThis->cbGuestRAM);
4024 if (RT_FAILURE(rc))
4025 return PDMDEV_SET_ERROR(pDevIns, rc,
4026 N_("Configuration error: Failed querying \"RamSize\" as a 64-bit unsigned integer"));
4027
4028 rc = CFGMR3QueryBoolDef(pCfg, "GetHostTimeDisabled", &pThis->fGetHostTimeDisabled, false);
4029 if (RT_FAILURE(rc))
4030 return PDMDEV_SET_ERROR(pDevIns, rc,
4031 N_("Configuration error: Failed querying \"GetHostTimeDisabled\" as a boolean"));
4032
4033 rc = CFGMR3QueryBoolDef(pCfg, "BackdoorLogDisabled", &pThis->fBackdoorLogDisabled, false);
4034 if (RT_FAILURE(rc))
4035 return PDMDEV_SET_ERROR(pDevIns, rc,
4036 N_("Configuration error: Failed querying \"BackdoorLogDisabled\" as a boolean"));
4037
4038 rc = CFGMR3QueryBoolDef(pCfg, "KeepCredentials", &pThis->fKeepCredentials, false);
4039 if (RT_FAILURE(rc))
4040 return PDMDEV_SET_ERROR(pDevIns, rc,
4041 N_("Configuration error: Failed querying \"KeepCredentials\" as a boolean"));
4042
4043 rc = CFGMR3QueryBoolDef(pCfg, "HeapEnabled", &pThis->fHeapEnabled, true);
4044 if (RT_FAILURE(rc))
4045 return PDMDEV_SET_ERROR(pDevIns, rc,
4046 N_("Configuration error: Failed querying \"HeapEnabled\" as a boolean"));
4047
4048 rc = CFGMR3QueryBoolDef(pCfg, "RZEnabled", &pThis->fRZEnabled, true);
4049 if (RT_FAILURE(rc))
4050 return PDMDEV_SET_ERROR(pDevIns, rc,
4051 N_("Configuration error: Failed querying \"RZEnabled\" as a boolean"));
4052
4053 rc = CFGMR3QueryBoolDef(pCfg, "GuestCoreDumpEnabled", &pThis->fGuestCoreDumpEnabled, false);
4054 if (RT_FAILURE(rc))
4055 return PDMDEV_SET_ERROR(pDevIns, rc,
4056 N_("Configuration error: Failed querying \"GuestCoreDumpEnabled\" as a boolean"));
4057
4058 char *pszGuestCoreDumpDir = NULL;
4059 rc = CFGMR3QueryStringAllocDef(pCfg, "GuestCoreDumpDir", &pszGuestCoreDumpDir, "");
4060 if (RT_FAILURE(rc))
4061 return PDMDEV_SET_ERROR(pDevIns, rc,
4062 N_("Configuration error: Failed querying \"GuestCoreDumpDir\" as a string"));
4063
4064 RTStrCopy(pThis->szGuestCoreDumpDir, sizeof(pThis->szGuestCoreDumpDir), pszGuestCoreDumpDir);
4065 MMR3HeapFree(pszGuestCoreDumpDir);
4066
4067 rc = CFGMR3QueryU32Def(pCfg, "GuestCoreDumpCount", &pThis->cGuestCoreDumps, 3);
4068 if (RT_FAILURE(rc))
4069 return PDMDEV_SET_ERROR(pDevIns, rc,
4070 N_("Configuration error: Failed querying \"GuestCoreDumpCount\" as a 32-bit unsigned integer"));
4071
4072 rc = CFGMR3QueryU64Def(pCfg, "HeartbeatInterval", &pThis->cNsHeartbeatInterval, VMMDEV_HEARTBEAT_DEFAULT_INTERVAL);
4073 if (RT_FAILURE(rc))
4074 return PDMDEV_SET_ERROR(pDevIns, rc,
4075 N_("Configuration error: Failed querying \"HeartbeatInterval\" as a 64-bit unsigned integer"));
4076 if (pThis->cNsHeartbeatInterval < RT_NS_100MS / 2)
4077 return PDMDEV_SET_ERROR(pDevIns, rc,
4078 N_("Configuration error: Heartbeat interval \"HeartbeatInterval\" too small"));
4079
4080 rc = CFGMR3QueryU64Def(pCfg, "HeartbeatTimeout", &pThis->cNsHeartbeatTimeout, pThis->cNsHeartbeatInterval * 2);
4081 if (RT_FAILURE(rc))
4082 return PDMDEV_SET_ERROR(pDevIns, rc,
4083 N_("Configuration error: Failed querying \"HeartbeatTimeout\" as a 64-bit unsigned integer"));
4084 if (pThis->cNsHeartbeatTimeout < RT_NS_100MS)
4085 return PDMDEV_SET_ERROR(pDevIns, rc,
4086 N_("Configuration error: Heartbeat timeout \"HeartbeatTimeout\" too small"));
4087 if (pThis->cNsHeartbeatTimeout <= pThis->cNsHeartbeatInterval + RT_NS_10MS)
4088 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
4089 N_("Configuration error: Heartbeat timeout \"HeartbeatTimeout\" value (%'ull ns) is too close to the interval (%'ull ns)"),
4090 pThis->cNsHeartbeatTimeout, pThis->cNsHeartbeatInterval);
4091
4092#ifndef VBOX_WITHOUT_TESTING_FEATURES
4093 rc = CFGMR3QueryBoolDef(pCfg, "TestingEnabled", &pThis->fTestingEnabled, false);
4094 if (RT_FAILURE(rc))
4095 return PDMDEV_SET_ERROR(pDevIns, rc,
4096 N_("Configuration error: Failed querying \"TestingEnabled\" as a boolean"));
4097 rc = CFGMR3QueryBoolDef(pCfg, "TestingMMIO", &pThis->fTestingMMIO, false);
4098 if (RT_FAILURE(rc))
4099 return PDMDEV_SET_ERROR(pDevIns, rc,
4100 N_("Configuration error: Failed querying \"TestingMMIO\" as a boolean"));
4101 rc = CFGMR3QueryStringAllocDef(pCfg, "TestintXmlOutputFile", &pThis->pszTestingXmlOutput, NULL);
4102 if (RT_FAILURE(rc))
4103 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed querying \"TestintXmlOutputFile\" as a string"));
4104
4105 /** @todo image-to-load-filename? */
4106#endif
4107
4108 /*
4109 * We do our own locking entirely. So, install NOP critsect for the device
4110 * and create our own critsect for use where it really matters (++).
4111 */
4112 rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
4113 AssertRCReturn(rc, rc);
4114 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->CritSect, RT_SRC_POS, "VMMDev#%u", iInstance);
4115 AssertRCReturn(rc, rc);
4116
4117 /*
4118 * Register the backdoor logging port
4119 */
4120 rc = PDMDevHlpIOPortRegister(pDevIns, RTLOG_DEBUG_PORT, 1, NULL, vmmdevBackdoorLog,
4121 NULL, NULL, NULL, "VMMDev backdoor logging");
4122 AssertRCReturn(rc, rc);
4123
4124#ifdef VMMDEV_WITH_ALT_TIMESYNC
4125 /*
4126 * Alternative timesync source.
4127 *
4128 * This was orignally added for creating a simple time sync service in an
4129 * OpenBSD guest without requiring VBoxGuest and VBoxService to be ported
4130 * first. We keep it in case it comes in handy.
4131 */
4132 rc = PDMDevHlpIOPortRegister(pDevIns, 0x505, 1, NULL,
4133 vmmdevAltTimeSyncWrite, vmmdevAltTimeSyncRead,
4134 NULL, NULL, "VMMDev timesync backdoor");
4135 AssertRCReturn(rc, rc);
4136#endif
4137
4138 /*
4139 * Allocate and initialize the MMIO2 memory.
4140 */
4141 rc = PDMDevHlpMMIO2Register(pDevIns, 1 /*iRegion*/, VMMDEV_RAM_SIZE, 0 /*fFlags*/, (void **)&pThis->pVMMDevRAMR3, "VMMDev");
4142 if (RT_FAILURE(rc))
4143 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
4144 N_("Failed to allocate %u bytes of memory for the VMM device"), VMMDEV_RAM_SIZE);
4145 vmmdevInitRam(pThis);
4146
4147 if (pThis->fHeapEnabled)
4148 {
4149 rc = PDMDevHlpMMIO2Register(pDevIns, 2 /*iRegion*/, VMMDEV_HEAP_SIZE, 0 /*fFlags*/, (void **)&pThis->pVMMDevHeapR3, "VMMDev Heap");
4150 if (RT_FAILURE(rc))
4151 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
4152 N_("Failed to allocate %u bytes of memory for the VMM device heap"), PAGE_SIZE);
4153
4154 /* Register the memory area with PDM so HM can access it before it's mapped. */
4155 rc = PDMDevHlpRegisterVMMDevHeap(pDevIns, NIL_RTGCPHYS, pThis->pVMMDevHeapR3, VMMDEV_HEAP_SIZE);
4156 AssertLogRelRCReturn(rc, rc);
4157 }
4158
4159 /*
4160 * Register the PCI device.
4161 */
4162 rc = PDMDevHlpPCIRegister(pDevIns, &pThis->PciDev);
4163 if (RT_FAILURE(rc))
4164 return rc;
4165 if (pThis->PciDev.devfn != 32 || iInstance != 0)
4166 Log(("!!WARNING!!: pThis->PciDev.devfn=%d (ignore if testcase or no started by Main)\n", pThis->PciDev.devfn));
4167 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, 0x20, PCI_ADDRESS_SPACE_IO, vmmdevIOPortRegionMap);
4168 if (RT_FAILURE(rc))
4169 return rc;
4170 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 1, VMMDEV_RAM_SIZE, PCI_ADDRESS_SPACE_MEM, vmmdevIORAMRegionMap);
4171 if (RT_FAILURE(rc))
4172 return rc;
4173 if (pThis->fHeapEnabled)
4174 {
4175 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 2, VMMDEV_HEAP_SIZE, PCI_ADDRESS_SPACE_MEM_PREFETCH, vmmdevIORAMRegionMap);
4176 if (RT_FAILURE(rc))
4177 return rc;
4178 }
4179
4180#ifndef VBOX_WITHOUT_TESTING_FEATURES
4181 /*
4182 * Initialize testing.
4183 */
4184 rc = vmmdevTestingInitialize(pDevIns);
4185 if (RT_FAILURE(rc))
4186 return rc;
4187#endif
4188
4189 /*
4190 * Get the corresponding connector interface
4191 */
4192 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThis->IBase, &pThis->pDrvBase, "VMM Driver Port");
4193 if (RT_SUCCESS(rc))
4194 {
4195 pThis->pDrv = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIVMMDEVCONNECTOR);
4196 AssertMsgReturn(pThis->pDrv, ("LUN #0 doesn't have a VMMDev connector interface!\n"), VERR_PDM_MISSING_INTERFACE);
4197#ifdef VBOX_WITH_HGCM
4198 pThis->pHGCMDrv = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIHGCMCONNECTOR);
4199 if (!pThis->pHGCMDrv)
4200 {
4201 Log(("LUN #0 doesn't have a HGCM connector interface, HGCM is not supported. rc=%Rrc\n", rc));
4202 /* this is not actually an error, just means that there is no support for HGCM */
4203 }
4204#endif
4205 /* Query the initial balloon size. */
4206 AssertPtr(pThis->pDrv->pfnQueryBalloonSize);
4207 rc = pThis->pDrv->pfnQueryBalloonSize(pThis->pDrv, &pThis->cMbMemoryBalloon);
4208 AssertRC(rc);
4209
4210 Log(("Initial balloon size %x\n", pThis->cMbMemoryBalloon));
4211 }
4212 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
4213 {
4214 Log(("%s/%d: warning: no driver attached to LUN #0!\n", pDevIns->pReg->szName, pDevIns->iInstance));
4215 rc = VINF_SUCCESS;
4216 }
4217 else
4218 AssertMsgFailedReturn(("Failed to attach LUN #0! rc=%Rrc\n", rc), rc);
4219
4220 /*
4221 * Attach status driver for shared folders (optional).
4222 */
4223 PPDMIBASE pBase;
4224 rc = PDMDevHlpDriverAttach(pDevIns, PDM_STATUS_LUN, &pThis->IBase, &pBase, "Status Port");
4225 if (RT_SUCCESS(rc))
4226 pThis->SharedFolders.pLedsConnector = PDMIBASE_QUERY_INTERFACE(pBase, PDMILEDCONNECTORS);
4227 else if (rc != VERR_PDM_NO_ATTACHED_DRIVER)
4228 {
4229 AssertMsgFailed(("Failed to attach to status driver. rc=%Rrc\n", rc));
4230 return rc;
4231 }
4232
4233 /*
4234 * Register saved state and init the HGCM CmdList critsect.
4235 */
4236 rc = PDMDevHlpSSMRegisterEx(pDevIns, VMMDEV_SAVED_STATE_VERSION, sizeof(*pThis), NULL,
4237 NULL, vmmdevLiveExec, NULL,
4238 NULL, vmmdevSaveExec, NULL,
4239 NULL, vmmdevLoadExec, vmmdevLoadStateDone);
4240 AssertRCReturn(rc, rc);
4241
4242 /*
4243 * Create heartbeat checking timer.
4244 */
4245 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, vmmDevHeartbeatFlatlinedTimer, pThis,
4246 TMTIMER_FLAGS_NO_CRIT_SECT, "Heartbeat flatlined", &pThis->pFlatlinedTimer);
4247 AssertRCReturn(rc, rc);
4248
4249#ifdef VBOX_WITH_HGCM
4250 pThis->pHGCMCmdList = NULL;
4251 rc = RTCritSectInit(&pThis->critsectHGCMCmdList);
4252 AssertRCReturn(rc, rc);
4253 pThis->u32HGCMEnabled = 0;
4254#endif /* VBOX_WITH_HGCM */
4255
4256 /*
4257 * In this version of VirtualBox the GUI checks whether "needs host cursor"
4258 * changes.
4259 */
4260 pThis->mouseCapabilities |= VMMDEV_MOUSE_HOST_RECHECKS_NEEDS_HOST_CURSOR;
4261
4262 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatMemBalloonChunks, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Memory balloon size", "/Devices/VMMDev/BalloonChunks");
4263
4264 /*
4265 * Generate a unique session id for this VM; it will be changed for each
4266 * start, reset or restore. This can be used for restore detection inside
4267 * the guest.
4268 */
4269 pThis->idSession = ASMReadTSC();
4270 return rc;
4271}
4272
4273/**
4274 * The device registration structure.
4275 */
4276extern "C" const PDMDEVREG g_DeviceVMMDev =
4277{
4278 /* u32Version */
4279 PDM_DEVREG_VERSION,
4280 /* szName */
4281 "VMMDev",
4282 /* szRCMod */
4283 "VBoxDDRC.rc",
4284 /* szR0Mod */
4285 "VBoxDDR0.r0",
4286 /* pszDescription */
4287 "VirtualBox VMM Device\n",
4288 /* fFlags */
4289 PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_DEFAULT | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
4290 /* fClass */
4291 PDM_DEVREG_CLASS_VMM_DEV,
4292 /* cMaxInstances */
4293 1,
4294 /* cbInstance */
4295 sizeof(VMMDevState),
4296 /* pfnConstruct */
4297 vmmdevConstruct,
4298 /* pfnDestruct */
4299 vmmdevDestruct,
4300 /* pfnRelocate */
4301 vmmdevRelocate,
4302 /* pfnMemSetup */
4303 NULL,
4304 /* pfnPowerOn */
4305 NULL,
4306 /* pfnReset */
4307 vmmdevReset,
4308 /* pfnSuspend */
4309 NULL,
4310 /* pfnResume */
4311 NULL,
4312 /* pfnAttach */
4313 NULL,
4314 /* pfnDetach */
4315 NULL,
4316 /* pfnQueryInterface. */
4317 NULL,
4318 /* pfnInitComplete */
4319 NULL,
4320 /* pfnPowerOff */
4321 NULL,
4322 /* pfnSoftReset */
4323 NULL,
4324 /* u32VersionEnd */
4325 PDM_DEVREG_VERSION
4326};
4327#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
4328
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use