VirtualBox

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

Last change on this file since 54805 was 54805, checked in by vboxsync, 10 years ago

Release log prefixes.

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette